Борьба с веб-скрейперами с помощью Rust

Вы когда-нибудь испытывали желание заставить нервничать людей, бродящих по интернету в поисках уязвимостей? Я  —  определенно да. Эта история о том, как я нашел способ наказать таких специалистов, затем использовал Rust для его усовершенствования, а затем уничтожил свой веб-сервер с помощью фургона.

1. Фаза раздражения

Если вы когда-нибудь запускали сайт (в независимости от масштаба) и случайно заглядывали в журнал доступа, то вскоре наверняка обнаруживали, что множество поступающих запросов не имеют никакого отношения к вашему сайту. Вместо этого многие из них обращаются к таким путям, как /wp-login.php , /.env и /.git/config. Оказывается, есть достаточно разных людей, которые либо хотят украсть пароль к вашей базе данных, либо пытаются войти на ваш сайт, построенный на WordPress. Хотя в этом нет ничего удивительного, но такие вещи немного раздражают при проверке статистики сайта.

Конечно, речь идет об автоматизированном процессе, хотя какой-нибудь маньяк может делать это и вручную (в интернете кого только нет). Обновление /robots.txt (файла, описывающего то, каким образом ботам разрешается проверять сайт) не поможет, потому что ни один уважающий себя бот, крадущий пароли, никогда не потрудится его прочитать. Однако крупные компании, такие как Google, относятся к этому файлу с должным уважением (за некоторыми исключениями). Можем ли мы как-то использовать этот факт в своих целях?

2. Фаза вхождения во врата ада

Конечно, да! Изучая способы борьбы с назойливыми ботами, я наткнулся на HellPot  —  HTTP-ловушку, предназначенную для уничтожения ботов, пытающихся скрейпить сайт, посредством передачи им того, что они хотят. Любой HTTP-запрос к HellPot по заданному пути (например, по вышеупомянутому /wp-login.php) будет встречен вечным потоком данных отсюда  —  “Рождение трагедии (эллинизм и пессимизм)” Фридриха Ницше (по внешнему виду это вполне похоже на сайт). Надо просто позаботиться о том, чтобы указать те же пути в robots.txt, чтобы bingbot не “читал” Ницше со скоростью в несколько Мб/с.

Как это возможно? Оказывается, HTTP-ответы могут быть потоковыми. Обычно такая особенность используется при передаче больших файлов. Это отлично подходит для наших целей: можно просто продолжать генерировать один и тот же ответ вечно, никогда не прерывая поток и не говоря “Готово!”.

Давайте учтем некоторые важные моменты:

  1. Большинство веб-скрейперов  —  это плохо написанные скрипты.
  2. Большинство веб-скрейперов работают на облачных экземплярах.
  3. Память и хранилище на этих экземплярах ограничены.
  4. И пропускная способность тоже.

Что же происходит, когда shiddy_wp_scraper.py подключается к сайту, который продолжает вечно отправлять данные? Как правило, он просто уничтожается! И если вы потребляете больше гигабайтов данных, чем у вас есть памяти, тогда ваша ОС решит, что некоторым процессам пора прекратиться, и вот вы получаете еще один уничтоженный веб-скрейпер! Остается только надеяться, что тот, кто его устанавливал, забыл добавить функцию автоматического перезапуска.

Впрочем, процесс не обязательно должен “упасть”. Есть и другие не менее интересные варианты развития событий:

  1. Сохранение на диск (в конце концов, это приведет к “падению”, когда место на диске будет исчерпано).
  2. Накопление платы за пропускную способность (если вы платите за нее).

Примечание: если у вас лимитное подключение или ограниченная пропускная способность, не рекомендую это делать, так как вы можете потерять больше, чем пираты, занимающиеся веб-скрейпингом!

3. Фаза прибавки жара в адском котле

Мне очень нравилось уничтожать веб-скрейперы с помощью HellPot, но я чувствовал, что процессу не хватает индивидуальной изюминки. Я немного поучаствовал в развитии HellPot, но Go  —  не мой родной язык, и этому инструменту уничтожению скрейперов не хватало некоторых желаемых мной функций. Что же я сделал? Конечно же, переписал его на Rust.

GitHub — ginger51011/pandoras_pot: A HellPot inspired HTTP honeypot to punish and educate unruly…
A HellPot inspired HTTP honeypot to punish and educate unruly web crawlers, written in Rust (🚀) …github.com

После небольшой доработки на Rust я опубликовал pandoras_pot на crates.io. Основной принцип тот же: отправка запроса, подключение, выполнение фатальных действий, “падение”. Но я взял на себя смелость и добавил несколько нужных мне фич:

  • Лучшая производительность. Rust, в конце концов, невероятно быстр. И безопасен.
  • Больше способов генерировать данные. Почему бы не отправлять статический файл снова и снова? Или же это могут быть просто случайные строки вместо вывода цепей Маркова (хотя этот инструмент поддерживает цепи Маркова с помощью моей библиотеки цепей Маркова markovish).
  • Полная свобода действий. Теперь вы как пользователь можете обеспечить злоумышленнику источник боли. Не нравится Ницше? Как насчет Канта? Вчерашней газеты? Любовной записки, которую вы отправили своей подружке в третьем классе?
  • Порт здоровья для активной балансировки нагрузки между экземплярами. Теперь боты будут играть в русскую рулетку. Либо они подключаются к Raspberry Pi со скромным выходом, либо к вашему игровому компьютеру со светодиодами, способному сокрушить даже самого отъявленного бота. Если светодиодного монстра нет в сети, балансировщик нагрузки выберет вместо него Pi!
  • Функции защиты от злоупотреблений, такие как максимальное количество одновременных потоков и ограничение скорости.

После итераций с pandoras_pot я достиг того уровня, который меня устраивает. И, конечно, вы можете опробовать его сами! В README содержится полное руководство по настройке.

Пример вывода pandoras_pot, наказывающего… локальный адрес

4. Фаза уничтожения веб-сервера с помощью фургона

Ну как, сработало? Отлично! Оказывается, многие боты любят скачивать данные. Здесь я мог бы разместить красивые графики входящих соединений. К несчастью, оказалось, что низкокачественный ПК, который я купил на парковке продуктового магазина 3 года назад и использовал в качестве веб-сервера, не выдержал поездки в кузове движущегося фургона. Кто бы мог предсказать такое? Думаю, морально я смогу от этого оправиться, а вот восстановить физически жесткий диск  —  вряд ли. И нет, я не создавал резервную копию журналов доступа, потому что в целях экономии на хранении предпочитаю сохранять резервные копии вещей, которые уж точно не потеряются.

Но у меня есть несколько скриншотов, и я могу поделиться своими наблюдениями! Ниже приведен скриншот страницы статистики, которую я наспех сделал для списка соединений с pandoras_pot какое-то время назад:

Топ загрузок к концу января. Позднее показатель загрузок достигал 25 ГБ(!) за раз

Прежде всего, большинство соединений поступает от публичных облачных провайдеров. Я подозревал, что большая часть трафика отправляется через сеть Tor, но проверка IP-адресов, потребляющих больше всего трафика, показала, что ни один из них не имел к ней отношения. Некоторые соединения поступали от облачных провайдеров, которые хвастались тем, что являются “приватными” и “анонимными”. Возможно, это уловка Агентства национальной безопасности, возможно, легитимный трафик. Не буду приводить здесь ссылки на них.

Еще одно интересное наблюдение: многие соединения загружают объемы, которые стремятся к “красивым” числам, таким как 2 ГБ, 3 ГБ и 0,5 ГБ. Не исключено, что на ботах установлен такой лимит на загрузку, но нет никаких причин для того, чтобы он был таким высоким. Думаю, на самом деле здесь идет речь о лимите памяти облачного провайдера. Проверка любого крупного облачного провайдера показывает, что оперативная память является одним из решающих факторов, когда речь идет о цене, и обычно эти лимиты устанавливаются в круглых числах (о каких шла речь выше). Думаю, что боты заполняют всю память текстом из “Страданий юного Вертера” и терпят крушение (но хотя бы, надеюсь, узнают что-то новое для себя в процессе).

Я также заметил, что таймаут у многих ботов настроен на 30 секунд. Поэтому имеет смысл сосредоточиться на производительности: у pandoras_pot есть 30 секунд, чтобы уничтожить несколько ботов. Это вполне реально, так как скорость может запросто достигать более 100 МБ/с в зависимости от вашего интернет-соединения и аппаратного обеспечения. Она может быть и гораздо выше, как в случае с моим старым ПК, обладавшим производительностью, сравнимой с тостером или, возможно, чайником.

Следует отметить, что важными факторами также остаются шифрование и сжатие. Кстати, о сжатии: похоже, есть люди, которые отвечают на вредоносные запросы с помощью Zip-бомб. Возможно, это будущая полезная функция?

5. Фаза генерации идей на будущее

Теперь мы можем уничтожить большинство плохо настроенных ботов, которые заходят на сайт. А как насчет дальнейших планов?

Все, кто когда-либо размещал на своем сайте поле “Связаться с нами”, знают, что есть такие боты, которые всегда смогут пройти через reCAPTCHA (особенно если вы продешевили на этапе реализации). Но ведь кнопка “Отправить” просто отправляет запрос на ваш сервер. Было бы печально, если бы она вела куда-то еще…

Можно также заниматься любыми видами “безумной” маршрутизации. Как насчет перенаправления подозрительного трафика? Ведь можно проверять входящие запросы на ресурсе AbuseIPDB, чтобы немедленно перенаправлять их.

Примечание: не перенаправляйте IP-адреса вслепую. Некоторым людям нужен Tor для доступа к свободному интернету. Есть и такие пользователи, которых провайдер заставляет делиться публичными адресами с другими.

Заключение

Когда вы создаете сайт, приготовьтесь к тому, что на него много кто будет заходить. Не всегда это будут живые люди. Большинство из таких посетителей безобидны, но если вы включили .env в публичный сайт, вас могут ждать неприятности.

Некоторые могут заметить, что злоумышленники теперь напишут лучших ботов, которые смогут обнаруживать pandoras_pot. Это, конечно, верно, но почему бы не помешать тем, кто этого не делает? Здесь есть одно преимущество: pandoras_pot может менять вид ответов с помощью конфигурации. Это гораздо проще, чем процесс обнаружения в коде. Чем больше людей используют собственные конфигурации для pandoras_pot, тем сложнее будет от него уйти.

Подытоживая, хочется сказать: ведите себя корректно и относитесь с уважением к файлу /robots.txt, иначе последствия будут непредсказуемыми.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Emil Jonathan Eriksson: Fighting back: Turning the Tables on Web Scrapers Using Rust

Предыдущая статьяПредставляем SafeTest: новый подход к тестированию фронтенда
Следующая статьяОсвоение различных видов линий в Jetpack Compose с помощью PathEffect