Как защитить форму SMS-авторизации от накрутки
Для компаний, которые отправляют через REDSMS SMS-коды при регистрации, входе и подтверждении операций. Здесь — как распознать накрутку SMS (SMS pumping), ограничить её последствия и настроить несколько уровней защиты.
Ограничение повторной отправки на один номер не защищает от бота, который запрашивает по одному SMS на тысячи разных номеров. Нужны лимиты на число разных получателей, контроль общего объёма и расходов и мониторинг подтверждённых кодов.
Что такое накрутка SMS
SMS pumping (накрутка SMS) — искусственное увеличение числа сообщений, обычно через публичную форму регистрации, входа или восстановления доступа. Бот запрашивает код, ваше приложение отправляет SMS, но пользователь не завершает подтверждение.
Результат для компании — рост расходов на SMS: все отправленные сообщения оплачиваются независимо от статуса доставки.
Типичный сценарий
- Бот находит публичную точку запроса кода — форму на сайте или её серверный API.
- Запрашивает коды на множество номеров, нередко по одному сообщению на номер.
- Ваше приложение отправляет SMS через REDSMS.
- Код никто не вводит, а расходы на отправки растут.
- Бот меняет номера, IP-адреса и параметры запросов, обходя простые лимиты.
Как распознать атаку
Обратите внимание на сочетание признаков:
- количество отправленных кодов резко выросло без роста реальных регистраций или входов;
- много новых номеров и мало повторных запросов на один номер;
- номера идут подряд, из одного диапазона или из стран, где у вас нет пользователей, — если вы ещё не ограничили страны (см. шаг 3);
- растёт число разных номеров с одного IP, устройства, сессии или группы связанных IP;
- растут расходы на авторизацию, а доля успешно подтверждённых кодов падает.
Важнее всего сравнивать отправки с результатом. Например, если SMS стало втрое больше, а успешных подтверждений столько же, — проверьте трафик. Универсального «нормального» соотношения нет: ориентируйтесь на исторические показатели своего продукта.
Частые причины атаки
Атаки производят с целью нанесения финансового ущерба, перегрузки системы или использования чужого API-ключа. Поэтому защита должна работать независимо от мотивов атакующего.
Чек-лист защиты
- Капча на форме авторизации, её токен проверяется на сервере
- Ключ API REDSMS не попадает в браузер или мобильное приложение
- Повторная отправка на номер — не чаще одного раза в 60 секунд
- Ограничено число кодов на один номер за сутки
- Ограничено число разных номеров, на которые можно запросить код с одного источника
- Есть лимит общего количества кодов и контроль расходов за период; проверка выполняется на сервере
- Разрешены только нужные страны и направления (для России — мобильные +79)
- В личном кабинете REDSMS включены ограничения и белый список IP
- Ведётся учёт отправленных и успешно подтверждённых кодов; проверка выполняется на сервере
- Настроены оповещения об аномалиях и понятен порядок действий при атаке
Значения лимитов в этом руководстве — примеры. Подберите их под свой трафик.
Шаг 1. Подключите капчу
Капча снижает число автоматических обращений, но не заменяет лимиты и анализ поведения. Главное правило: токен капчи проверяется на вашем сервере до отправки SMS. Если проверять только в браузере, бот обойдёт её, обратившись к серверу напрямую.
Для аудитории в России удобна Yandex SmartCaptcha, популярный зарубежный вариант — Cloudflare Turnstile.
Yandex SmartCaptcha
-
Создайте капчу в консоли Yandex Cloud и получите два ключа: ключ клиента (для страницы) и серверный ключ (только для сервера, никому не передавайте).
-
Добавьте виджет в фо рму:
<script src="https://smartcaptcha.cloud.yandex.ru/captcha.js" defer></script>
<form method="post" action="/auth/send-code">
<input name="phone" type="tel" autocomplete="tel" placeholder="+7 900 000-00-00" required>
<div class="smart-captcha" data-sitekey="<КЛЮЧ_КЛИЕНТА>"></div>
<button type="submit">Получить код</button>
</form>После прохождения капчи в форму автоматически добавляется скрытое поле
smart-token. -
На сервере, до отправки SMS, проверьте токен:
POST https://smartcaptcha.cloud.yandex.ru/validateс параметрамиsecret(серверный ключ),tokenи, по возможности,ip(IP пользователя). Капча пройдена, если в ответе"status": "ok". Отсутствующий или недействительный токен — это не пройденная проверка.
Заранее реши те, что делает сайт, если сервис капчи недоступен: для чувствительных операций безопаснее не отправлять SMS без дополнительной проверки.
Cloudflare Turnstile
Работает так же: виджет <div class="cf-turnstile" data-sitekey="..."> со скриптом https://challenges.cloudflare.com/turnstile/v0/api.js, токен приходит в поле cf-turnstile-response. На сервере проверьте его запросом к https://challenges.cloudflare.com/turnstile/v0/siteverify с параметрами secret, response и remoteip; капча пройдена, если "success": true. Не доверяйте одному факту отображения виджета в браузере.
Запретите встр аивание ваших страниц в чужие сайты заголовком Content-Security-Policy: frame-ancestors 'self'. Это полезно против отдельных сценариев злоупотребления интерфейсом, но не защищает от накрутки SMS само по себе.
Шаг 2. Ограничьте частоту и число получателей
Все ограничения проверяйте на своём сервере до обращения к API REDSMS.
| Что ограничить | Пример начального порога | Для чего |
|---|---|---|
| Повторная отправка на один номер | Не чаще 1 раза в 60 секунд | Предотвратить частые повторы |
| Коды на один номер | Не более 5 за 24 часа | Ограничить расходы на одного получателя |
| Запросы с одного IP | Не более 10 за 10 минут | Снизить частоту прямых запросов |
| Разные н омера с одного IP или сессии | Не более 3 за час | Помешать перебору получателей — главный признак накрутки |
| Общий объём кодов | Порог по обычному трафику | Сдержать распределённую атаку |
| Расход на авторизацию | Бюджет и пороги предупреждения на вашей стороне | Ограничить финансовые потери |
При накрутке боты отправляют по одному SMS на множество разных номеров. Ограничение повторов на один номер такую атаку не остановит. Атакующий может распределять запросы между множеством IP, поэтому учитывайте и совокупный объём, уникальные номера, диапазоны получателей, сессии и долю подтверждённых кодов.
Подбирайте значения под свою аудиторию: несколько добросовестных пользователей могут выходить в интернет с одного IP — корпоративная сеть, мобильный оператор. В таких случаях вместо безусловной блокировки по IP запрашивайте дополнительную проверку.
Для счётчиков используйте атомарные операции и временные окна в Redis или похожем хранилище. Проверка лимита и резервирование квоты должны выполняться согласованно при параллельных запросах. Не продлевайте окно при каждом запросе, если нужен фиксированный лимит за период.
Шаг 3. Отправляйте коды только с сервера
Правильная цепочка: браузер пользователя → сервер вашего сайта → проверка номера, капчи и лимитов → API REDSMS → результат отправки → проверка введённого кода.
- Ключ API REDSMS хранится только на сервере — никогда в HTML, JavaScript или мобильном приложении.
- Защитите серверный метод отправки кода так же, как форму: капча и лимиты проверяются в нём самом.
- Проверяйте формат и страну номера. Если ваши пользователи только в России, принимайте мобильные номера
+79и отклоняйте остальные. Это грубый первичный фильтр, а не полноценная валидация номера. Учтите: код+7общий у России и Казахстана — мобильные номера Казахстана начинаются с+77.
Что должен делать сервер
- Получить номер, токен капчи и контекст запроса.
- Привести номер к международному формату.
- Проверить, разрешены ли страна и направление.
- Проверить капчу на сервере.
- Атомарно проверить и зарезервировать лимиты: номер, IP, сессия, уникальные номера, общий объём.
- Если для пользователя ещё действует выданный код, не создавать новое сообщение без необходимости.
- Сгенерировать криптографически случайный одноразовый код.
- Сохранить его безопасный проверочный эквивалент (например, хеш) с коротким сроком действия и привязкой к операции.
- Вызвать API REDSMS и проверить HTTP-ответ и результат API.
- Записать событие и результат отправки в журнал.
- При вводе кода проверить срок действия и число попыток, а после успеха сразу сделать код недействительным.
Для типовой SMS-авторизации подойдут шестизначный код, короткий срок действия (например, 3–5 минут) и жёсткое ограничение числа попыток ввода.
Пример серверной логики (Python)
Это схема, а не готовый код для копирования: адаптируйте её под свой язык и фреймворк, а поля и способ подписи запроса сверяйте с актуальной документацией API REDSMS.
import hashlib, secrets, time
import redis, requests
r = redis.Redis()
ALLOWED_PREFIXES = ("+79",) # мобильные РФ; добавьте "+77", если есть пользователи из Казахстана
def captcha_ok(token, ip):
resp = requests.post("https://smartcaptcha.cloud.yandex.ru/validate",
data={"secret": SMARTCAPTCHA_SERVER_KEY, "token": token, "ip": ip},
timeout=3)
return resp.ok and resp.json().get("status") == "ok"
def within_limit(key, limit, window_sec):
pipe = r.pipeline()
pipe.incr(key)
pipe.expire(key, window_sec, nx=True) # окно задаётся один раз и не продлевается
count, _ = pipe.execute()
return count <= limit
def unique_phones_ok(ip, phone, limit=3, window_sec=3600):
key = f"phones:{ip}"
pipe = r.pipeline()
pipe.sadd(key, phone)
pipe.expire(key, window_sec, nx=True)
pipe.scard(key)
_, _, count = pipe.execute()
return count <= limit
def send_code(phone, ip, captcha_token):
if not captcha_ok(captcha_token, ip):
return "Пройдите проверку"
if not (phone.startswith(ALLOWED_PREFIXES) and len(phone) == 12):
return "Неверный номер"
if not within_limit(f"phone:60s:{phone}", 1, 60):
return "Повторная отправка через 60 секунд"
if not (within_limit(f"phone:day:{phone}", 5, 86400)
and within_limit(f"ip:10m:{ip}", 10, 600)
and unique_phones_ok(ip, phone)):
return "Слишком много запросов, попробуйте позже"
code = f"{secrets.randbelow(1_000_000):06d}"
save_code(phone, code) # ваша функция: сохранить хеш кода на 3–5 минут, с лимитом попыток
ts = str(time.time())
signature = hashlib.md5((ts + REDSMS_API_KEY).encode()).hexdigest()
resp = requests.post("https://cp.redsms.ru/api/message",
headers={"login": REDSMS_LOGIN, "ts": ts, "secret": signature},
json={"route": "sms", "from": SENDER_NAME, "to": phone,
"text": f"Код для входа: {code}"},
timeout=10)
if not (resp.ok and resp.json().get("success")):
log_send_error(phone, resp) # ваша функция: журнал ошибок отправки
return "Не удалось отправить код, попробуйте позже"
return "Код отправлен"
Принятие сообщени я API ещё не означает доставку абоненту: статус доставки приходит позже (метод GET /api/message/{uuid} или Webhook).
Как не допустить лишних повторов
- Показывайте таймер: «Отправить код повторно через 60 с».
- Не отправляйте новое SMS автоматически при перезагрузке страницы.
- Если код ещё действует, предложите дождаться его, а не сразу создавайте новый.
Шаг 4. Включите ограничения в личном кабинете REDSMS
Это вторая линия защиты: она сработает, даже если что-то пропустит ваш сайт.
| Настройка | Где | Что даёт |
|---|---|---|
| Суточный лимит отправленных сообщений | Настройки → Ограничения | Верхняя граница количества отправок за сутки |
| Максимум одинаковых сообщений на номер за сутки | Настройки → Ограничения | Ограничивает повторы одинакового текста на один номер |
| Интервал, в течение которого сообщения на номер считаются дубликатами | Настройки → Ограничения | Отсекает частые одинаковые отправки |
| Белый список IP для API | Настройки → HTTP API | Запросы не с ваших серверов получат ответ 401 |
Суточные лимиты сбрасываются в 03:00 по Москве. Подбирайте общий лимит с учётом ожидаемого числа регистраций и пикового трафика.
- Белый список IP защищает ваш ключ от использования с чужих серверов, но не ост ановит бота, который обращается к публичной форме вашего сайта: в этом случае SMS отправляет ваш собственный сервер — с разрешённого IP.
- Лимит дубликатов не заменяет защиту от массовой отправки на разные номера. К тому же из-за разных одноразовых кодов тексты SMS отличаются друг от друга.
- Суточный лимит ограничивает количество сообщений, а не сумму расходов. Денежный порог настраивайте на своей стороне.
Шаг 5. Отслеживайте аномалии и расходы
Собирайте события не только об отправке SMS, но и об успешном подтверждении кода — вторые есть только на стороне вашего сайта. Детализацию отправок смотрите в личном кабинете REDSMS: число сообщений, номера, страны.
| Показатель | Что показывает |
|---|---|
| Отправленные коды в час и за сутки | Необычные скачки объёма |
| Уникальн ые номера-получатели | Массовый перебор абонентов |
| Доля успешных подтверждений | Приводят ли отправки к реальной авторизации |
| SMS на одно успешное подтверждение | Изменение эффективности канала |
| Расходы по направлениям | Рост стоимости отдельных стран и сетей |
| Запросы по IP и сессиям | Концентрацию или распределение подозрительной активности |
| Причины отказов и срабатывания лимитов | Поведение ботов и влияние защиты на обычных пользователей |
Не задавайте универсальное правило вроде «1,2 SMS на один успешный вход». Рассчитайте собственный базовый уровень — например, за предыдущие 2–4 недели — и ищите отклонения с учётом времени суток, сезонности и маркетинговых кампаний. Для регистрации, входа и восстановления пароля могут понадобиться разные пороги.
Настройте автоматические оповещения о резком росте числа уникальных получателей и суммарной стоимости отправок. Подозрительные запросы лучше отправлять на дополнительную проверку, чем блокировать всех пользователей сразу.
Если накрутка уже идёт
- Ограничьте ущерб: временно снизьте суточный лимит в личном кабинете REDSMS (Настройки → Ограничения) и отключите в своём приложении неиспользуемые международные направления.
- Усильте серверные проверки: капча, лимит разных номеров, ограничения по IP и сессии из шагов 1–2.
- Разберите трафик: когда начался рост, какие страны, диапазоны номеров и источники запросов задействованы.
- Проверьте ключ API: если есть признаки, что он попал к посторонним, сгенерируйте новый и включите белый список IP (Настройки → HTTP API).
- Напишите в поддержку REDSMS: укажите логин, период аномалии, направления и примеры сообщений — мы оценим детализацию и подскажем, какие можно установить ограничения в личном кабинете.
- После атаки пересмотрите пороги и настройте оповещения, чтобы следующий всплеск заметить раньше.
Не отключайте подтверждение кодом целиком, не оценив последствия для пользователей: для рискованных запросов лучше временно включить дополнительную проверку.
Другие способы подтверждения
В зависимости от сценария можно рассмотреть другие каналы REDSMS:
| Канал | Как работает |
|---|---|
| Telegram | Код приходит в Telegram; оплата только за доставленные коды |
| Wait Call | Пользователь сам звонит на номер для подтверждения |
| Flash Call | Код — последние цифры номера входящего звонка |
| SIM-PUSH / Mobile ID | Подтверждение одним нажатием во всплывающем окне на телефоне |
| Voice | Код озвучивается голосовым звонком |
Доступность, тарифы, ограничения и условия доставки каждого канала можно уточнить у вашего менеджера.
Переход с SMS на звонок или другой платный канал сам по себе не устраняет риск накрутки: для любого способа подтверждения нужны лимиты, контроль получателей и мониторинг расходов.
Коротко: минимальная безопасная конфигурация
Чтобы быстро снизить риск, начните с пяти мер: серверная капча, лимит уникальных номеров с одного источника, общий лимит кодов, защита ключа API и мониторинг доли подтверждённых кодов. Затем настройте контроль расходов, разрешённые направления и порядок действий при аномалиях.