Pull to refresh

Comments 50

Как планируется выявлять и отрабатывать false positive?
В базе есть поле counter — сколько раз IP-адрес добавляли в базу. По нему вполне можно определить плохиш это, или просто F5 залипло.
Чего я точно ещё не сделал, так это механизм whitelist-а для поисковиков. В теории, они запросто могут давать подозрительную активность. Доверять спискам из интернета не стоит (?), да и Google не рекомендует так делать. Вместо этого предлагают проверять с помощью User-Agent-а и обратного разрешения IP-адреса. Всё это с лёгкостью можно сделать в скрипте.
Если не затруднит объясните в чем разница между

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 100;

и

limit_req_zone $binary_remote_addr zone=dynamic:10m rate=2r/s;
limit_req zone=dynamic burst=10 nodelay;

Из доки, тоже как то не очевидно, в каких случаях что использовать.
limit_conn perip устанавливает предел количества установленных с одного IP соединений
limit_req_zone — количество обращений с одного адреса, которое допустимо за секунду

В рамках одного соединения может быть множество обращений. Соединение может длиться долго, а обращения могут происходить с разной интенсивностью.
Вот здесь было разрешено 100 соединений с 1 IP (это важно для клиентов, которые за NAT), но при этом более 2 запросов в секунду нельзя формировать.

И к сожалению, при использовании SPDY, ограничить скорость обработки запросов нельзя, поэтому пришлось отключить. А жаль — технология реально ускоряющая загрузку страницы.
Если читать внимательнее, то там написано про limit_rate.
Упс, прошу прощения, это писатель доки ошибся, не туда ссылку поставил.
Скорость обработки запросов в SPDY-соединении не может быть ограничена.
И ссылка на документацию ngx_http_limit_req_module.

По-моему, однозначно написано. Да и логично, т.к. в SPDY отдельные запросы мультиплексируются в один пакет данных. И в теории, в одном HTTP-запросе может прийти вся страничка целиком — с текстом, картинками и скриптами.
Эм… то что вы написали не имеет ничего общего с реальностью, даже в представлении о том, как работает SPDY.

На самом же деле все гораздо прозаичнее. Модуль limit_req работает совсем на другом уровне. Речь там о директиве limit_rate, ограничивающей bandwidth на ответ, просто потому что в nginx этот интерфейс реализован на уровне соединения, и им воспользоваться не получилось, нужно свой городить ещё выше.

В процессе редактирования доки кто-то неправильно понял оригинальный limitation, а я не вчитался и упустил этот момент. Исправим.
Да уж, иногда, оказывается, нужно читать не только доки, но и сам патч.
Спасибо!
limit_conn — ограничение на количество одновременно обрабатываемых запросов.
limit_req — ограничение на частоту поступления/обработки запросов.
UFO landed and left these words here
C Cloudflare не доводилось работать, но был опыт с Amazon и Heroku. Ничего плохого не скажу, на всякий товар найдётся свой покупатель. Пока ещё dedicated-серверы могут конкурировать с «облаками» как по аптайму, так и по цене. Ну и философско-шкурный вопрос — если «не изобретать велосипед» и отдавать услугу (хостинг/администрирование) на откуп «дядькам с большими квадратными головами» (фраза знакомых из Intel-а), то самому придётся зарабатывать чем-то другим.
из запретил доступ со всех IP, не принадлежащих им
Вот этого не понял. Разъясни, пожалуйста.
Cloudflare — это не хостинг. Это CDN+Защита от DDoS + WAF. Причем базовый тариф бесплатен.
В моём понимании CDN — это тоже хостинг, узко-специализированный. Про CloudFlare я очень высокого мнения, особенно после атаки на Спамхаус.
Бесплатный звучит заманчиво, возможно он даже очень хорош, но вот бесплатный Heroku вызывает только слёзы, а платный широко раскрывает глаза.
А вообще всё надо считать — у меня была ситуация, когда «CDN» из пяти «серверов» на Intel Atom оказался выгодней настоящих CDN-ов.
Т.е. если как-то можно грубо оценить нагрузку, то я беру dedicate, а если нагрузка может расти до облаков — то и хоститься там же.
Бесплатный тариф cloudflare с легкостью заменит решение, описанное в посте. И сделает это более продуманно, в том числе с автоматической отработкой ложных срабатываний, анализом и защитой на L7, ну и, собственно, распределением кеша контента по континентам.
Как академическое упражнение пост весьма полезен. Но на сегодняшний момент для большинства проектов мелкого и среднего уровня (да и крупного, чего уж там) гораздо выгоднее отдать эту тему на аутсорс таким конторам, как cloudflare, а усилия свои направить на улучшение/доработку функционала ресурса и наполнение его контентом.
UFO landed and left these words here
эм а разве без nginx нельзя ограничивать кол-во соединений с одного IP?
примерно так:
iptables -p tcp --dport 80 -m iplimit --iplimit-above 20 --iplimit-mask 24 -j REJECT
еще есть такой модуль помоему:
iptables -I INPUT 1 -p tcp --dport 80 -m string --string «GET / HTTP/1.0» --algo kmp -j DROP
От DDoS-а это не спасаёт, так как атакующих много. Да и в пределах одного keep-alive соединения можно порядочно насолить.
А в случае с SPDY (VBart, поправьте меня, если ошибаюсь) соединение и так будет всего одно.
Это совершенно разного уровня ограничения. С помощью модуля limit_conn ограничивается не количество соединений, а количество одновременно обрабатываемых запросов (в документации это названо «активными соединениями»). Keep-alive соединений при этом может быть больше. А со SPDY может быть соединение одно, а параллельных запросов в нём много.
Пользуясь случаем хочу пропиарить решение знакомых людей, которое связыват лог апача с бан таблицами и мне очень неплохо помогало:
github.com/unicodefreak/log2ban

Для совсем тяжелых случаев (тысячи в секунду) не очень походит, для описанной ситуации более чем.
В посте упоминался fail2ban, который делает то же самое
Респект! Почерпнул оттуда идею — надо вместе с IP хранить в базе хэш URL-а, тогда плохишей будет легче отделять, они действительно ломятся (как правило) по одному адресу. А если начнут бегать по всему дереву форума? Решение хорошее, но всё равно парсер логов, от которого я пытался избавиться. Да и от логов тоже можно избавляться — нечего им убивать SSD-шку или отжирать память в tmpfs-е. В идеале — лог — это только средство отладки (ИМХО).
Не могли бы вы рассказать, почему не помог fail2ban, о принципах атаки ботов, как они его обходят в то же время загружая систему?
fail2ban помог, но я описал его недостатки — при высокой нагрузке на WEB-сервер, он уже сам по себе является тормозящим фактором (усиливающим эффект атаки?). Вот например, при ~800 запросах в секунду (это только на динамику), у нас лог вылетает со скоростью ~ 200кб/с
В данном случае это недостаток polling-архитектуры, логичнее и быстрее event/interrupt подход, что я и сделал.

Атаки, что я наблюдал у себя, были двух видов:
— не прекращающийся POST на регистрацию в форуме — вероятно спамеры подбирают логины
— ярко выраженный волнообразный наплыв однообразных запросов с нескольких сотен адресов
А по моему сейчас если можно защититься программными средствами от атаки уже ддосом не назвать… Вот если прийдет реальный syn-flood или udp flood то там дело до фаерволла или любого иного ПО даже не дойдет. Все остальное это в открытом доступе баловство с которым справляется и iptables и nginx.
Да, все так. Подобные методы работают только для пионер-атак, типа «уснул на кнопке F5» или «ололо, пацаны, я в первый раз скачал ab, такая крутая штука».
Увы, даже ab или whiletruedo программы это было популярно когда nginx еще и лимитить не умел ничего, сейчас в доступе уже вещи потяжелее, от которых Ваш хостер может в лучше случае перецепить адрес на nullroute. А что обиднее всего что это все еще и продавать умудряются, не говоря уж о полноценноп ботнете.
«вещи потяжелее» — это hping или Mausezahn, например? :)
dns amplification штуковины, как пример вещей потяжелее.
dns amplification это не штуковины, это метод атаки.
а разве это дерево комментариев не с методов началось? :) методы и инструменты в руках скрипткидди — синонимы.
Вот как раз в руках скрипткидди есть только инструменты. Но при чем тут скрипткидди?
А по моему сейчас если можно защититься программными средствами от атаки
Cпорный вопрос — на многих аппаратных фаерволах установлены вполне себе программные операционные системы, и даже Linux. Так что это, ИМХО, вопрос терминологии.
уже ддосом не назвать…
Если атака с большого количества адресов приводит к деградации или недоступности сервиса — то это есть чистый DDoS, по определению.

С серьёзным SYN-флудом пока не сталкивался. Да и статья не про этот тип атаки.
Решение с CGI скриптом забавное, но я не понимаю, почему именно CGI? Мне кажется вы могли бы аналог этого bash скрипта на том же PHP написать и не извращаться с fcgiwrap
Во-первых, извращаться с fcgiwrap не пришлось — он у меня уже был настроен для collectd. Думаю что у многих так же.
Во-вторых, я тоже сразу подумал про PHP, но нужно, чтобы скрипт выполнялся от рута. А для этого пришлось бы подымать ещё один экземпляр php-fpm и запускать его от рута, что громоздко и не красиво.
Дать пользователю, с которым выполняется php-fpm, права на sudo /usr/sbin/ipset add ... не думали?
Думал, но ИМХО, это потенциальная дырка в безопасности, ну и exec() нужно разрешать, что мне не очень нравится.
Мне кажется CGI-скрипт на bash, выполняющийся с высочайшими привилегиями, потенциально большая дыра в безопасности, чем очень ограниченное право на выполнение команды через sudo.
Придумать пример, как скомпрометировать сервер с разрёшенным ipset из PHP кода довольно несложно, особенно на хостинге с массой разношёрстных пользователей. А вот как это сделать с моим CGI скриптом я пока не нашёл. Поможете?
Например, есть некий пользователь samowar. Через sudoers мы даём ему такое право:

samowar ALL = NOPASSWD: /usr/sbin/ipset add web_black_list *.*.*.* timeout 600

Как пользователь samowar сможет скомпрометировать сервер если разрешена только такая команда? Расскажите, очень интересно.
Он может добавить в чёрный список адреса важных клиентов, таким образом лишив их доступа к сервису, может вырастить список до размеров, когда это станет проблемой для ядра (добавив туда весь Интернет (шутка).

Кроме того, sudo у меня не используется, почти с таким же успехом можно поставить SUID на ipset.

На продакшен серверах я использую spawn-fcgi, не через localhost:1234 как в примере (потому что это потенциально очень опасно), а через unix socket, на который выставлены права 700 для nginx:nginx. Сам CGI-скрипт тоже с такими правами.

Таким образом, сделать что-то плохое, можно только скомпрометировав nginx. Я в него свято верю. Но вы правы — потенциально это тоже небезопасно. Какие могут быть ещё варианты?
Если злодей сможет через sudo добавить в блок-лист важных клиентов на 10 минут, то значит у него есть доступ к выполнению других произвольных команд или изменению кода, что в свою очередь означает что лишение доступа важных клиентов — лишь малая толика того, что этот злодей может сделать. Я бы даже сказал что вам очень повезет если злодей окажется настолько глуп что заблокирует важных клиентов, которые в свою очередь об это сообщат вам. Не о том беспокоиться надо.
Не совсем уловил идею, почему вы пишете «значит у него есть доступ к выполнению других произвольных команд или изменению кода». Если я вас правильно понял, вы предлагаете разрешить из PHP-кода выполнение ipset от рута. О каких других произвольных командах идёт речь?
sudo вы будете разрешать выполнять через exec(), верно?
Допустим. Ну там ещё есть вагон функций, через которые можно запускать.
Собственно всё очевидно, кроме, разве что, SQLite. Я его добавил пока просто для статистики, но в принципе можно использовать и для удаления устаревших плохишей из черного списка. Время 5 минут пока тоже не используется.

Ipset позволяет задать как дефолтный timeout хранения записей в списке так и определять его индивидульно для каждой записи (для особо злостных адресов, например).
Очень удобно. Не надо городить механизм очисти списка.
Согласен, для простой конфигурации — очень удобно. Но если надо выявлять злостных плохишей, то нужна статистика, а она в базе. Кроме того база пригодится для создания white-list-ов. Скорее всего оптимальныйм будет гибридный вариант: использовать таймаут, для того чтобы не тулить в cron скрипт по удалению старых записей, а базу использовать для сбора статистики и решения о том, на сколько банить очередного плохиша, т.е. первый раз засветился — на три минуты, второй раз — на 10 и т.п.

P.S.: Очень люблю статистику, просто млею от rrd графиков.
Что в вашем понимании злостный плохиш? И причем тут статистика?
ДДос они в африке ддос. Он может быть умным, может быть тупым. Но в любом случае, главным во время ддоса будет выживание ресурса, а не вычисление кто плохиш а кто чесный пионер.
Если с адреса идёт 100500 реквестов в секунду то лучше его блокировать на неделю для профилатики и написать письмо владельцу адреса. Это в разы эфективнее.
Статистика как раз и нужна для того, чтобы узнать сколько было блокировок, и на основе этого задавать время очередной блокировки.
Например, если мы знаем, что IP уже блокировался 20 раз, то при очередной попытке напакостить — баним на неделю, т.к. он — злостный плохиш.

Про писать письмо — интересный вопрос. Когда мне валит спам спам с определённого IP — я нахожу владельца или провайдера (так как это относительно несложно), и как правило дело решается. Но когда твой сервер грузит некий IP из динамического DSL-пула где-то в Екатеринбурге, то я очень сомневаюсь, что смогу до кого-то достучаться. Ну и раз это DDoS, то таких адресов много, всем не напишешь.

Пару IP я для любопытства отслеживал — они начинают и заканчивают отмечаться примерно в одно и то же время, очень похоже на домашний компьютер с трояном.
Only those users with full accounts are able to leave comments. Log in, please.