Потік скрейперів на безкоштовному тарифі Cloudflare: що його зупинило і що ми залишили вимкненим
Операції
Одного ранку одна з наших карток товарів перестала відкриватися. Cloudflare показував відвідувачам помилку 524, сервер обробляв кожну сторінку від двох до шести хвилин, і нічого не сповіщало про це приблизно десять годин. Причиною був скрейпер, який проходив через резидентні проксі зі швидкістю близько 225 запитів на секунду.
Форма потоку
- Тисячі адрес, по одному-три запити з кожної. Домашні широкосмугові з'єднання в США, Іспанії, Франції, Бразилії, Великобританії та інших країнах, тобто трафік, який здають в оренду мережі резидентних проксі.
- Chrome user agent на Mac з номерами версій від 103 до 151.
- Майже ніколи немає cookie або Referer. Із 2697 запитів, які ми вибірково перевірили на сервері, лише 4 містили cookie і 4 — Referer.
- Два типи клієнтів. Приблизно половина не надсилала заголовки
Sec-Fetch-*та підказки клієнта: це скрипт зі скопійованим рядком user agent. Інша половина надсилала повні браузерні заголовки: це headless-браузер.
Кожна сторінка рендерилася для кожного запиту, тому кожен воркер ставив у чергу сотні рендерів і впирався в ліміт CPU.
Чому ліміти на адресу не допомогли
Обмеження частоти рахує запити з однієї адреси. Якщо з тисяч адрес надходить по одному-три запити, жодна окрема адреса ніколи не наближається до ліміту. Блокування країн заблокувало б наших відвідувачів. Те, що скрейпер не міг дешево підробити, — це поведінка браузера, який уже був на сайті.
На межі Cloudflare: три безкоштовні правила
Безкоштовний тариф дозволяє п'ять власних правил WAF на зону. Ми використали три, усі з керованим викликом (managed challenge), а не блокуванням, щоб людина, яка потрапила під правило помилково, могла пройти далі:
- Фейковий браузер: GET-запит, у якому user agent містить
Chrome/і немає заголовкаSec-Fetch-Mode. Кожен Chrome, починаючи з 2019 року, його надсилає. - Хмари скрейперів: запит до сторінки з мереж Alibaba, Tencent і Huawei Cloud, звідки надходила більшість запитів, які ми перевіряли.
- Аварійне, вимкнено за замовчуванням: GET-запит без жодного cookie і без Referer. Людина, яка вже була на сайті, або яка прийшла за посиланням, проходить без перешкод; скрейпер, який не зберігає cookie, отримує виклик на кожному запиті. Ми вмикаємо його лише під час потоку, тому що він також ставить виклик людині, яка вводить адресу в свіжому браузері.
Усі три пропускають верифікованих ботів Cloudflare, user agent, що називають себе роботами, наші власні адреси, шляхи API та webhook, а також файли, які не є сторінками. Через два дні потік усе ще тривав: за одну годину правило фейкових браузерів поставило під сумнів понад 10 000 запитів. 10 000 подій, які повертає Cloudflare на запит, надійшли з 9 627 адрес, жодна з яких не мала більше 4.
На початковому сервері: шлюз у застосунку
Безголовна частина має повні заголовки браузера, тому лише крайові правила не зупиняють її, коли аварійне правило вимкнене. В самому застосунку ми поставили невеликий проміжний шар перед рендерером сторінок:
- user agent Chrome без
Sec-Fetch-Modeі без підказок клієнта отримує 403, перш ніж виконується будь-яка робота; - незнайомець, без наших cookies і без Referer, отримує обслуговування лише тоді, коли у воркера є вільна потужність, із швидкістю кілька сторінок на секунду. Якщо перевищено, сторінка 503 розміром 400 байтів встановлює cookie та перезавантажується через дві секунди. Людина отримує сторінку з другої спроби; скрапер, що не зберігає cookies, ніколи не отримує.
За першу хвилину шлюз відхилив близько 6 700 фейкових браузерів і відвернув близько 6 700 незнайомців, обслуговуючи незнайомців зі швидкістю близько 9 сторінок на секунду. Повільні запити впали до нуля, навантаження CPU воркерів знизилось з їхнього ліміту до 12–15 відсотків, а пам’ять — з 4–5 ГБ на кожен до 0,65 ГБ.
Що ми залишили вимкненим
- Bot Fight Mode. Він ставить під сумнів автоматизований трафік, і на безкоштовному тарифі його не можна обійти власним правилом; він також чіпляв webhook нашого платіжного провайдера.
- Режим Under Attack для всієї зони. Він проганяє кожного відвідувача, клієнта API та webhook через проміжну сторінку. Аварійне правило робить те саме, але лише для запитів на сторінки від незнайомців.
- Правило обмеження частоти запитів на безкоштовному тарифі. Воно рахує за адресою, а цей потік ніколи не виводить його за межі.
- Блокування AI-краулерів. Ми хочемо, щоб нас знаходили AI-пошукові асистенти, і ті краулери не були проблемою.
Головний висновок
Потік через резидентні проксі легко впізнати за тим, чого бракує: заголовки browser fetch, cookies і Referer. Ставте під сумнів це на краю, тримайте незнайомців у межах того, що ваші воркери можуть відрендерити, і переконайтеся, що щось поза сервером помітить, коли сторінка перестане відкриватися. Night Watch пакує всі три: вартовий, правила з автоматичним перемиканням для аварійного та шлюз для Python-вебзастосунків.