Как защитить форму от спама

Disclaimer

  1. Каждый отдельный метод (и даже все вместе) — не гарантирует защиту, но снижает вероятность и ущерб, увеличивает стоимость атаки.

  2. Значения параметров в примерах можно менять.

  3. Методы могут (и должны) комбинироваться и дополняться.

  4. Примеры на PHP являются лишь иллюстрацией.

  5. Цель — не сделать атаку невозможной, но дороже выгоды.

  6. Некоторые тезисы и примеры имеют допущения и нюансы, развитие описания которых не уместить в рамках этой заметки.

Кому это выгодно:

  1. Конкурентам: расход бюджета на уведомления конкурентами (по аналогии со скликиванием контекстной рекламы).

  2. Конкурентам: жалобы на спам от абонентов, штрафы от операторов и регуляторов.

  3. Конкурентам: нарушение нормальной работы формы регистрации или сайта для легитимных пользователей.

  4. Спамерам: дешевый способ “бомбинга” определенных абонентов на заказ.

  5. Спамерам: фейковые регистрации.

1. Задержка перед повторным запросом

Атакующему выгодна возможность выполнить максимальное количество запросов за минимальное время с одного устройства. Повторный запрос кода подтверждения с одного IP адреса или на один номер следует разрешать не ранее, чем через 90-120 секунд. А лучше - увеличивать это время с каждым повторным запросом. Эту проверку следует осуществлять не только в интерфейсе браузера, но и на серверной стороне.


$ip = $_SERVER['REMOTE_ADDR'];
$phone = $_POST['phone'];
$isLimited = apcu_fetch($ip) || apcu_fetch($phone);
apcu_store($ip, 1, 90);
apcu_store($phone, 1, 90);
if ($isLimited) {
    // deny
}



Как улучшить: использовать browser fingerprinting [1] [2] и exponential backoff [1] [2].

2. Ограничение количества запросов с одного IP

IPv4 адреса в мире закончились, а их аренда стоит денег, что увеличивает стоимость ресурсов атакующего. Адреса IPv6 же практически бесплатны и безграничны, потому поддержку IPv6 лучше отключить.

Стоимость аренды 1 IPv4 адреса ~100₽, а отправки SMS — ~4₽, что делает невыгодным атаку при <20 запросов с одного IP. Пример ограничения для 5 запросов с одного IP в сутки:


$ip = $_SERVER['REMOTE_ADDR'];
$hits = apcu_fetch($ip) ? apcu_inc($ip) : intval(apcu_store($ip, 1, 86400));
if ($hits > 5) {
    // deny
}


Как улучшить: автоматически добавлять IP-адреса в запрещенные на уровне фаервола или веб-сервера [1] [2] [3] [4]. В примитивном варианте это может выглядеть так:


if ($hits > 5) {
    @fwrite(fopen('/var/log/spam.log', 'a'), "deny $ip;\n");
}

// nginx.conf:
server {
    include /var/log/spam.log;
    allow all;

// crontab:
*/5 * * * * /etc/init.d/nginx reload

3. Ограничение количества запросов на один номер

При отправке сообщения через api.greensms.ru повторный запрос идёт альтернативным маршрутом, чтобы гарантировать доставку. Последующее сообщения будут направлены теми же маршрутами, потому, если предположить, что они по каким-то причинам не были получены — дальнейшие повторы нецелесообразны.

Пример ограничения для 5 запросов на один номер в сутки:


$phone = $_POST['phone'];
$hits = apcu_fetch($phone) ? apcu_inc($phone) : intval(apcu_store($phone, 1, 86400));
if ($hits > 5) {
    // deny
}

Как улучшить: начиная с 3-го запроса использовать код в номере, входящий звонок, код голосом, VK, WhatsApp, Viber вместо SMS; запретить отправку в страны, в которых нет ваших пользователей.

4. Использование CSRF-токена

Наличие в форме уникального одноразового токена и его проверка на серверной стороне немного усложняет задачу атакующему, поскольку гарантируют, что запрос отправлен лишь после предварительной загрузки формы. Детали примере Laravel можно почерпнуть из документации.

Как улучшить: проверять, отправлен ли запрос посредством AJAX [1], использовать SameSite Cookie [1]

5. Использование Google reCAPTCHA v3

reCAPTCHA v3 является “скрытой” формой проверки, не требующей со стороны пользователя решения задач или ввода текста. В результате работы сервис возвращает значение в диапазоне от 0 до 1, означающее вероятность того, что пользователь — человек.

На практике, значения от 0,3 могут присваиваться легитимным пользователям, потому для полноценной фильтрации могут быть использованы лишь значения <0,3. В остальных случаях необходима комбинация с другими методами, возможность пользователю подтвердить, что он не робот другим способом.

Помимо этого, поскольку метод использует browser fingerprinting — наблюдаются ботнеты, способные стабильно показывать результат в 0,9. Всплеск активности на скриншоте — нелегитимный трафик с оценкой 0,9.


Как улучшить: дополнить отображением reCAPTCHA v2 в сомнительных случаях, например при оценке в диапазоне 0,3-0,7 или повторных действиях.


6. Блокировка нежелательного трафика

Если вы не ведете бизнес в каких-либо регионах, вы можете ограничить для них доступ или блокировать отправку на соответствующие номера.
Можно ограничить доступ для известных ботов и инструментов разработки на основе заголовков User-Agent и Referer.

Как улучшить: блокировать IP адреса дата-центров и хостинг-провайдеров.

7. Сервисы фильтрации трафика

Cloudflare, Qrator, DDoS-Guard предлагают не только решения по защите от DDoS, но и от ботов. Но и это не панацея.



Поддержка GREENSMS