Как обрабатывать истечение срока действия OTP-кода в SMS API

Как обрабатывать истечение срока действия OTP-кода в SMS API

Когда срок действия одноразового кода истёк, сервер должен отклонить его и дать пользователю запросить новый. Для этого нужно хранить время окончания срока, ограничивать повторные запросы и связывать проверку с последним выданным кодом. Отдельно защитите сценарий, в котором старое SMS приходит после нового: пользователь должен понимать, какой код вводить, а API — не принимать устаревшее значение. Ниже — схема тайм-аутов, повторной отправки и защиты от гонок, которую можно проверить до запуска.

Что происходит, когда срок действия OTP истёк?

При создании OTP-сессии сервер сохраняет идентификатор пользователя или операции, хеш кода, время выдачи, срок окончания и статус. Сам код отправляется через SMS API, а в базе хранится его хеш: при проверке система сравнивает введённое значение с ним, не записывая код в открытом виде.

Проверка должна сначала определить, существует ли активный код и не истёк ли его срок. Если время окончания уже прошло, API возвращает понятный результат, например «код истёк», и не продолжает проверку совпадения. Точные названия ошибок зависят от формата API, но клиентскому приложению нужно различать истечение срока, неверный код и слишком частые запросы.

Срок отсчитывайте по времени сервера, а не по часам телефона или браузера. Например, если запрос на проверку и истечение кода произошли почти одновременно, именно серверное время определяет, какой результат получит клиент.

Как настроить повторный запрос кода?

Кнопка повторной отправки должна создавать новую версию OTP для той же операции. Старый код после этого становится недействительным, даже если его срок ещё не закончился. Иначе у пользователя окажутся два подходящих кода, а приложение не сможет однозначно понять, какой из них считать актуальным.

Для каждой сессии храните номер версии или идентификатор выдачи. При повторном запросе сервер атомарно повышает версию, сохраняет новый хеш и ставит SMS в очередь. В SMS полезно написать, что действует только последний полученный код. Если первое сообщение задержалось и пришло позже второго, это предупреждение уменьшит путаницу.

Ограничьте частоту запросов и число попыток ввода. Интервал и лимиты задайте по сценарию: вход в аккаунт, подтверждение заказа или другая операция могут требовать разных настроек. Счётчики связывайте с сессией и операцией, чтобы повторный запрос не обнулял неудачные попытки ввода без отдельного решения системы.

Если SMS-шлюз вернул ошибку, покажите пользователю, что сообщение не отправлено, и разрешите повторить запрос согласно установленному ограничению. Не создавайте новый код при каждом обновлении страницы: один запрос должен соответствовать одной задаче отправки. Для защиты от повторной постановки одной и той же задачи пригодится схема защиты SMS API и SMPP от дублей.

Как защитить проверку от гонок?

Гонка возникает, когда два запроса одновременно проверяют или обновляют одну OTP-сессию. Например, пользователь дважды нажал «Отправить код», а сервер обработал оба запроса параллельно. Если оба запроса прочитают старую версию до сохранения новой, система может отправить два разных кода и оставить непредсказуемый активный код.

Обновляйте состояние сессии одной атомарной операцией: проверяйте текущую версию и меняйте её только при совпадении ожидаемого значения. Альтернативный вариант — транзакция с блокировкой записи на время изменения. Ключ идемпотентности для запроса повторной отправки помогает вернуть результат уже созданной задачи, если клиент повторил тот же запрос из-за сетевой задержки.

При проверке кода применяйте тот же принцип. Сервер должен проверить срок и версию, затем отметить код использованным в одной транзакции. Иначе два почти одновременных запроса с одним правильным кодом могут оба получить успешный ответ. Для операции, которую код подтверждает, зафиксируйте отдельный статус выполнения, чтобы повторная проверка не запустила её второй раз.

Как проверить сценарий до запуска?

Проверьте не только успешную доставку SMS, но и переходы между состояниями OTP-сессии. Запишите в журнал идентификатор операции, версию кода, время создания задачи, ответ API, результат доставки и итог проверки. Сам код в журнал не добавляйте. Если отправка проходит через SMPP, отдельно учитывайте ответ на submit_sm и DLR: подтверждение принятия сообщения шлюзом ещё не означает, что телефон получил его.

  • Введите верный код до окончания срока, затем повторите проверку после истечения.
  • Запросите новый код и убедитесь, что предыдущий сразу перестал подходить.
  • Отправьте два одинаковых запроса повторной отправки и проверьте, что очередь не создала две задачи.
  • Проверьте два параллельных запроса с одним кодом: успешным должен быть только один.
  • Смоделируйте задержку SMS и убедитесь, что позднее сообщение не возвращает старую версию в активное состояние.

Типичные ошибки:

  • Считать срок действия по времени устройства пользователя.
  • Оставлять старый код действительным после повторной отправки.
  • Обнулять лимит попыток ввода при каждом новом запросе без отдельного правила.
  • Создавать задачу SMS при каждом повторе одного и того же API-запроса.
  • Считать ответ шлюза о принятии сообщения подтверждением доставки на телефон.

Начните с одной тестовой операции: зафиксируйте срок действия, повторную отправку и правило, по которому предыдущий код теряет силу. Затем проверьте истечение, задержку SMS и два параллельных запроса. Когда логика работает в тесте, подключайте её к основному сценарию уведомлений.

Дата публикации: 26 октября 2026 года.