OTP-коды через SMS: TTL, повторы и защита от фрода
Как спроектировать отправку одноразовых кодов через SMS: срок действия, лимиты попыток, идемпотентность, повторные отправки, DLR и резервные каналы.

Содержание
- Из каких компонентов состоит OTP-сценарий
- TTL: сколько должен жить код
- Повторная отправка без дублей
- Лимиты проверки и защита от перебора
- Какие статусы нужны от SMS-платформы
- Когда включать резервный канал
- Схема API-интеграции
- Метрики, которые показывают качество сценария
- Чек-лист перед запуском
- Практический вывод
SMS с одноразовым кодом — только транспорт. Безопасность сценария определяют серверная проверка, короткий срок действия кода, ограничения на запросы и попытки ввода, защита журналов и понятное поведение при задержке доставки. Если эти элементы не согласованы, даже стабильно работающий SMS-шлюз не защитит вход или подтверждение операции.
Из каких компонентов состоит OTP-сценарий
Надёжный процесс лучше разделить на четыре независимых слоя:
- бизнес-сервис создаёт запрос на подтверждение конкретного действия;
- сервис аутентификации выпускает одноразовый код и хранит его проверочное представление;
- коммуникационная платформа передаёт сообщение оператору и возвращает идентификатор отправки;
- сервис аутентификации принимает код, проверяет срок действия, число попыток и связь с исходным действием.
Код нельзя считать самостоятельным доказательством личности. Его следует связывать с идентификатором операции, пользователем или сессией, а для чувствительных действий — дополнять оценкой риска и другими факторами.
TTL: сколько должен жить код
Срок действия должен быть достаточно длинным для обычной сетевой задержки, но не превращать код в долгоживущий пароль. Универсального числа нет: его выбирают по сценарию, измеренной задержке доставки и уровню риска. Вход в кабинет, подтверждение платежа и изменение контактных данных требуют разных правил.
Сервер обязан проверять время выпуска, а не доверять таймеру в интерфейсе. После успешного подтверждения код немедленно становится недействительным. Новый код обычно должен аннулировать предыдущий для той же операции, иначе пользователь может получить несколько сообщений и случайно применить устаревшее значение.
Практическое правило: сначала измерьте P95 и P99 времени доставки на рабочем трафике, затем задайте TTL с контролируемым запасом. Если редкие задержки постоянно выходят за окно, нужно улучшать маршрут или резервный сценарий, а не бесконечно увеличивать срок жизни кода.
Повторная отправка без дублей
Кнопка «Отправить ещё раз» создаёт сразу три риска: лишние расходы, несколько действующих кодов и возможность массово отправлять сообщения на чужой номер. Поэтому повтор должен проходить через серверные ограничения.
- Установите минимальный интервал между запросами.
- Ограничьте число отправок на номер, учётную запись, сессию и сетевой источник.
- Используйте идентификатор запроса и идемпотентность, чтобы повтор HTTP-запроса не создавал новое SMS.
- Не запускайте вторую отправку только потому, что DLR ещё не пришёл: статус доставки может задерживаться.
- После достижения лимита переводите пользователя в безопасный альтернативный процесс, а не сообщайте точную причину блокировки злоумышленнику.
Если используется резервный провайдер или канал, оркестратор должен хранить единый статус операции. Иначе два независимых маршрута могут доставить разные коды почти одновременно.
Лимиты проверки и защита от перебора
Длина кода сама по себе не заменяет контроль попыток. Сервер ограничивает количество неверных вводов для конкретного OTP-запроса и применяет более широкие лимиты к пользователю, номеру и источнику запросов. После исчерпания попыток код блокируется, даже если его TTL ещё не закончился.
Код не следует хранить или писать в журналы открытым текстом. Для проверки достаточно защищённого производного значения и серверного секрета. Доступ к журналам, очередям и трассировкам ограничивают, а номер телефона маскируют там, где полное значение не нужно для эксплуатации.
Особенно важно не раскрывать через ответы API, зарегистрирован ли номер в системе. Одинаковые внешние сообщения и сопоставимое время ответа уменьшают риск перебора существующих учётных записей.
Какие статусы нужны от SMS-платформы
Интеграции недостаточно ответа «запрос принят». Для эксплуатации нужны как минимум:
- внутренний идентификатор OTP-запроса;
- идентификатор сообщения у коммуникационной платформы;
- время создания, принятия платформой, передачи оператору и получения финального DLR;
- нормализованный статус и исходный код ошибки;
- маршрут или группа маршрутов без раскрытия чувствительных данных;
- признак повтора и выбранного резервного канала.
Принятое платформой сообщение ещё не доставлено на устройство. Подробнее о различиях между статусами и показателях качества — в руководстве по метрикам доставки SMS.
Когда включать резервный канал
Резервирование полезно только при заранее определённых условиях. Например, если сообщение не было принято оператором, можно выбрать другой SMS-маршрут; если срок подтверждения почти закончился, пользователю можно предложить голосовой вызов, push или подтверждение внутри приложения. Автоматическая повторная отправка во все каналы сразу создаёт дубли и ухудшает пользовательский опыт.
Резервный канал не должен обходить правила безопасности основного. Он использует тот же идентификатор операции, общий лимит попыток и единое решение о том, действителен ли код. Для операций высокого риска доступность канала не должна автоматически снижать требования к подтверждению.
Схема API-интеграции
Минимальный контракт удобно строить вокруг ресурса подтверждения, а не вокруг отдельного SMS:
POST /verificationsсоздаёт операцию и возвращает непрозрачныйverification_id;- сервис асинхронно отправляет уведомление через QuickTel или другую коммуникационную платформу;
- webhook обновляет транспортные статусы, но не принимает решение об успешной аутентификации;
POST /verifications/{id}/checkпроверяет код и атомарно закрывает операцию;- повторная отправка создаётся отдельной командой с ключом идемпотентности и общими лимитами.
Секреты API хранят вне кода, запросы к webhook проверяют, а повторную доставку событий обрабатывают идемпотентно. Общие варианты подключения разобраны в сравнении SMPP и HTTP API.
Метрики, которые показывают качество сценария
Одной доли доставленных SMS недостаточно. Команда должна видеть:
- долю кодов, доставленных внутри целевого окна;
- P50, P95 и P99 времени от запроса до DLR;
- конверсию из запроса OTP в успешное подтверждение;
- долю повторных отправок и резервных каналов;
- число неверных попыток, блокировок и запросов сверх лимита;
- расхождение между доставкой сообщения и успешным вводом кода;
- ошибки по операторам, маршрутам, регионам и шаблонам.
Резкий рост повторов при стабильном DLR может указывать на задержку сообщения, непонятный интерфейс или проблемы с шаблоном. Высокая доставка при низкой конверсии требует проверки всего пользовательского пути, а не только SMS-провайдера.
Чек-лист перед запуском
- Код связан с конкретной операцией и одноразово закрывается.
- TTL и лимиты задаются на сервере.
- Новый код аннулирует предыдущий по определённому правилу.
- Есть ограничения по номеру, пользователю, сессии и источнику.
- Код и полный номер не попадают в обычные журналы.
- Повторы API не создают дубли благодаря идемпотентности.
- DLR не используется как единственное доказательство личности.
- Резервный канал разделяет общие лимиты и статус операции.
- Алерты учитывают задержку, конверсию и признаки злоупотребления.
- Команда регулярно тестирует задержки, недоступность маршрута и повтор webhook.
Практический вывод
Безопасный OTP через SMS начинается не с текста сообщения, а с модели состояния: одна операция, ограниченный срок, ограниченное число попыток и наблюдаемый путь доставки. QuickTel может быть транспортным и интеграционным слоем для корпоративных SMS, однако правила выпуска и проверки кода остаются ответственностью бизнес-системы.
Перед промышленным запуском согласуйте нагрузку, требуемую пропускную способность, маршрутизацию, webhook и резервирование. Для критичных операций проведите отдельное моделирование угроз и не используйте SMS как единственный защитный механизм.


