Нашествие скраперов на бесплатном тарифе Cloudflare: что его остановило и что мы оставили выключенным
Операции
Одним утром наш сайт с объявлениями перестал открываться. Cloudflare показывал посетителям ошибку 524, origin-сервер обрабатывал страницу за две-шесть минут, и примерно десять часов нам об этом ничего не сообщало. Причиной был скрапер, проходивший через резидентные прокси со скоростью около 225 запросов в секунду.
Форма нашествия
- Тысячи адресов, по одному-трем запросам с каждого. Домашние широкополосные подключения в США, Испании, Франции, Бразилии, Великобритании и других странах, тот самый трафик, который сдают в аренду сети резидентных прокси.
- Пользовательские агенты Chrome на Mac с номерами версий от 103 до 151.
- Почти никогда нет cookie или Referer. Из 2697 запросов, которые мы выбрали на сервере, 4 содержали cookie и 4 — Referer.
- Два типа клиентов. Примерно половина не отправляла заголовки
Sec-Fetch-*и client hints: это скрипт с копией строки user agent. Вторая половина отправляла полные браузерные заголовки: это headless-браузер.
Каждая страница рендерилась для каждого запроса, поэтому каждый воркер ставил в очередь сотни рендеров и упирался в лимит CPU.
Почему лимиты на адрес не помогли
Rate limit считает запросы на адрес. При одном-трех запросах с каждого из тысяч адресов ни один адрес не приближается к лимиту. Блокировка стран отсекла бы наших посетителей. То, что скрапер не мог дешево подделать, — это поведение браузера, который уже бывал на сайте.
На edge Cloudflare: три бесплатных правила
Бесплатный тариф позволяет использовать пять пользовательских правил WAF на зону. Мы использовали три, все с managed challenge вместо блокировки, чтобы человек, попавший под правило по ошибке, мог пройти проверку:
- Фейковый браузер: GET-запрос, в котором user agent содержит
Chrome/и нет заголовкаSec-Fetch-Mode. Любой Chrome с 2019 года его отправляет. - Скраперские облака: запрос страницы из сетей Alibaba, Tencent и Huawei Cloud, откуда шло много того, что мы проверяли.
- Аварийный режим, по умолчанию выключен: GET-запрос без cookie вообще и без Referer. Человек, который уже был на сайте, или тот, кто приходит по ссылке, проходит без изменений; скрапер, который не хранит cookie, получает challenge на каждый запрос. Мы включаем его только во время нашествия, потому что он также проверяет того, кто вводит адрес в свежий браузер.
Все три пропускают проверенных ботов Cloudflare, пользовательские агенты, называющие себя роботами, наши собственные адреса, пути API и вебхуков, а также файлы, не являющиеся страницами. Спустя два дня поток не прекращался: за один час правило для фейковых браузеров отправило на проверку более 10 000 запросов. 10 000 событий, возвращаемых Cloudflare за один запрос, пришли с 9 627 адресов, ни с одного из них не было больше 4.
На исходном сервере: шлюз в приложении
Безголовая половина имеет полные заголовки браузера, поэтому только правил на уровне edge недостаточно, пока аварийное правило выключено. В самом приложении мы поставили небольшой middleware перед рендерером страниц:
- пользовательский агент Chrome без
Sec-Fetch-Modeи без client hints получает 403 до начала любой работы; - незнакомцу, без наших cookie и без Referer, страницы отдаются только при наличии свободной мощности у воркеров, со скоростью несколько страниц в секунду. При превышении лимита отдается страница 503 размером 400 байт, устанавливается cookie и происходит перезагрузка через две секунды. Человек получает страницу со второй попытки; скрапер, не сохраняющий cookie, не получает ее никогда.
За первую минуту шлюз отклонил около 6 700 фейковых браузеров и около 6 700 незнакомцев, отдавая незнакомцам около 9 страниц в секунду. Медленные запросы упали до нуля, загрузка CPU воркеров снизилась с предельной до 12–15 процентов, а потребление памяти — с 4–5 ГБ на каждый воркер до 0,65 ГБ.
Что мы оставили выключенным
- Bot Fight Mode. Он проверяет автоматизированный трафик, и на бесплатном тарифе его нельзя пропустить собственным правилом; он также перехватывал вебхуки нашего платежного провайдера.
- Режим Under Attack для всей зоны. Он пропускает каждого посетителя, клиента API и вебхук через промежуточную страницу. Аварийное правило делает то же самое, но только для запросов страниц от незнакомцев.
- Правило ограничения частоты запросов на бесплатном тарифе. Оно считает запросы по адресам, чего этот поток никогда не вызывает.
- Блокировка ИИ-краулеров. Мы хотим, чтобы нас находили ИИ-поисковые ассистенты, и эти краулеры не были проблемой.
Главный вывод
Поток через резидентные прокси легко распознать по отсутствующим элементам: заголовкам fetch браузера, cookie и Referer. Проверяйте это на уровне edge, ограничивайте незнакомцев тем, что могут отрендерить ваши воркеры, и убедитесь, что что-то вне сервера замечает, когда страница перестает открываться. Night Watch упаковывает все три компонента: watchdog, правила с автоматическим переключением для аварийного и шлюз для веб-приложений на Python.