Как защитить SMS API от накрутки OTP и лишних расходов

Начните с серверного ограничения запросов: проверяйте право на отправку SMS до обращения к провайдеру. Чтобы защитить SMS API от накрутки одноразовых кодов, нужны лимиты по номеру и источнику запросов, пауза между отправками, защита от дублей и контроль расходов. Кнопка с таймером на сайте эту задачу не решает: бот обращается к API напрямую. Ниже разберём, где поставить проверки, как учесть повторы и какие показатели вывести в мониторинг, чтобы ограничить расходы без остановки всех уведомлений.
Где возникает накрутка запросов на OTP?
OTP — одноразовый код, которым пользователь подтверждает действие, например вход в личный кабинет. Обычно сайт принимает запрос, создаёт код и передаёт SMS провайдеру. Если между запросом и отправкой нет серверных проверок, злоумышленник может многократно запускать этот сценарий. Расходы возникают даже тогда, когда никто не вводит код.
Уязвимым бывает и обычный повторный запрос. Пользователь нажал кнопку ещё раз, приложение повторило обращение после сбоя связи, фоновый обработчик заново взял задачу. Без общей проверки каждое обращение запускает отдельную отправку. Поэтому защита от накрутки начинается с того же механизма, который предотвращает случайные дубли.
Проверьте, кто вправе обращаться к SMS-провайдеру. Секретный API-ключ должен оставаться на сервере: браузер или мобильное приложение запрашивает код у вашего приложения, а уже оно решает, разрешить ли отправку. Если ключ доступен на клиентской стороне, ограничения формы можно обойти прямым запросом к провайдеру.
Для небольшого бизнеса в Беларуси практично сначала разобрать один сценарий, например вход по коду. Нарисуйте его путь: форма, серверная проверка, очередь, SMS-шлюз, ответ провайдера. Отметьте все места, откуда приложение запускает отправку, включая повторные задачи.
Какие проверки поставить перед отправкой SMS?
Проверки должны работать на сервере и охватывать все пути отправки OTP. Если сайт соблюдает лимит, а мобильное приложение использует отдельный маршрут без ограничений, защита остаётся неполной. Начните с общего обработчика, через который проходят запросы на код.
- Проверьте допустимость действия. Сервер должен распознавать сценарий, для которого пользователь запросил код, и разрешать только предусмотренный тип SMS.
- Ограничьте частоту запросов к одному номеру. Приводите номер к единому формату до проверки, чтобы варианты записи не создавали отдельные лимиты.
- Ограничьте запросы от одного источника. Учитывайте IP-адрес и сессию, но не полагайтесь только на IP: через один адрес могут работать разные пользователи.
- Добавьте паузу перед повторной отправкой. Проверяйте её на сервере, а в интерфейсе показывайте, когда можно запросить SMS снова.
- Проверьте общий предел отправок или расходов для OTP. После его достижения останавливайте новые запросы на код и отправляйте уведомление ответственному сотруднику.
Конкретные пороги выбирайте по обычному потоку запросов и доступному бюджету. Начните с отчёта по штатной работе: сколько кодов запрашивают, как часто повторяют запрос и в какое время появляется нагрузка. Лимит без такой проверки способен заблокировать покупателей во время обычного всплеска посещений.
Капчу можно включать при подозрительной активности, но она не заменяет ограничения на сервере. Также проверьте, какие направления нужны вашему бизнесу: если сервис обслуживает только определённые страны, лишние направления стоит закрыть в приложении и, при наличии такой настройки, у провайдера.
Как остановить дубли и параллельные запросы?
Проверка лимита и разрешение отправки должны выполняться как единая операция. Иначе параллельные запросы увидят одно и то же свободное место в лимите и каждый поставит SMS в очередь. Разработчику нужно проверить именно этот случай: несколько одновременных обращений к одному сценарию, когда запас лимита почти исчерпан.
Для повторов одного действия используйте ключ идемпотентности — идентификатор, по которому сервер узнаёт уже принятый запрос. Повтор с тем же ключом должен возвращать состояние прежней операции без новой SMS. При этом ключ не заменяет лимиты: злоумышленник может присылать новые идентификаторы при каждом обращении.
Разделите повтор запроса и повторную отправку кода. Если пользователь обновил страницу после нажатия кнопки, это ещё не основание создавать SMS заново. Отдельно задайте правило, когда разрешена новая отправка и что происходит с предыдущим кодом. Эти решения связаны с тем, как обрабатывать истечение срока действия OTP-кода.
Таймаут тоже не подтверждает, что SMS не ушла. Приложение могло не получить ответ, хотя шлюз уже принял сообщение. Сначала выясните возможности провайдера: поддерживает ли он идемпотентность или проверку состояния запроса по вашему идентификатору. Если таких возможностей нет, автоматический повтор после неопределённого результата требует отдельного правила, иначе он создаст дубль. Этот случай разобран в статье о защите API и SMPP от повторной отправки SMS.
Как связать лимиты, очередь и контроль расходов?
Поставьте проверку бюджета до помещения SMS в очередь. Уже готовые к отправке задачи тоже расходуют доступный запас: если учитывать только сообщения с ответом провайдера, очередь успеет накопить дополнительные отправки. Для контроля нужен резерв под задачи, которые приложение приняло в работу.
Резерв освобождают по понятному правилу. Например, задача отменена до обращения к шлюзу или провайдер однозначно отклонил запрос. При таймауте нельзя сразу считать, что отправки не было. Иначе приложение освободит запас, примет новые задачи и потеряет контроль над общей суммой.
Предел по количеству запросов не равен пределу в белорусских рублях. Стоимость зависит от условий провайдера, направления и числа частей SMS. Для финансового ограничения используйте актуальные тарифы и сверяйте расчёт приложения с отчётом провайдера. Если у него есть собственный лимит расходов, настройте его как дополнительный барьер и уточните, как он учитывает сообщения в обработке.
Разделите очередь OTP и очередь остальных уведомлений хотя бы на уровне правил и приоритетов. Тогда всплеск запросов на вход не займёт весь доступный поток отправки. При блокировке OTP проверяйте право на отправку и у задач, которые уже ждут в очереди, иначе накопленная нагрузка продолжит уходить в шлюз.
В мониторинге полезно отдельно видеть запросы кодов, блокировки по лимитам, принятые шлюзом сообщения и расходы. Если запросов стало больше, а отправок нет, ограничения сработали. Если число принятых сообщений растёт без сопоставимого роста успешных подтверждений кода, проверьте источник запросов и правила повторов.
Статус доставки SMS не показывает, завершил ли пользователь вход. Поэтому техническую аналитику шлюза нужно сопоставлять с событиями приложения. При настройке API-интеграции заранее определите, кто отвечает за очередь, кто меняет лимиты и кто получает сигнал о скачке расходов. Это конкретные требования к интеграции и аналитике трафика.
Типичные ошибки при защите SMS API
- Таймер работает только в интерфейсе. Причина обхода — сервер принимает повторные запросы без проверки паузы. Перенесите ограничение в общий обработчик отправки.
- Защита учитывает только IP-адрес. Блокировка затрагивает пользователей с общим адресом и пропускает запросы с разных адресов. Добавьте ограничения по номеру и общему объёму OTP.
- Счётчик обновляется после отправки. Параллельные обращения успевают пройти проверку. Резервируйте доступный лимит до постановки задачи в очередь.
- После любого таймаута приложение отправляет SMS заново. Результат первого запроса остаётся неизвестным. Проверяйте его состояние и используйте идемпотентность там, где её поддерживает провайдер.
- Общий выключатель останавливает все сообщения. Вместе с OTP пропадают другие уведомления. Выделите отдельное правило блокировки запросов на код.
Проверять защиту лучше в тестовом окружении с заглушкой SMS-шлюза: так повторные и параллельные запросы не создадут платных отправок. Признак работающей схемы — один допустимый запрос создаёт одну задачу, повтор возвращает её состояние, а превышение лимита не доходит до провайдера. Сейчас откройте форму входа и найдите адрес запроса, который уходит при нажатии «Получить код»: с этого маршрута начните проверку серверных ограничений.


