13 янв. 2015 г.

Разгружаем и защищаем север nginx с помощью fail2ban

Разгружаем и защищаем север nginx с помощью fail2ban

Задача: простыми для самоучки средствами максимально разгрузить сервер и/или ВДС-ВПС от множества дурных запросов.

Два вида паразитных запросов:
  • роботы как роботы
  • роботы как люди
Вводная: роботы как люди хитрят и меняют:
  • юзерагент через 5-100 запросов, но ИП меняют редко;
  • ИП через 5-100 запросов, но юзерагент меняют редко;
  • лимитировать по числу коннектов и/или их скорости/частоте не хочется, потому что в век скоростного интернета и 128 поточных браузеров потеряем много юзеров и гуглоботов.
Идея:
  • роботам как роботам сразу отдаём ошибку 444 по юзерагенту;
  • роботам как людям сразу отдаём ошибку 444 по специфичным подстрокам в URI запроса;
  • баним найденные ИП на часок, чтобы робот отдохнул и выкинул наш сервер из своей базы данных.
Реализация:



\etc\nginx\nginx.conf

http {
...
  log_format main_post '$remote_addr [$time_local] $host "$request" '
  '$status $body_bytes_sent [$request_body] "$http_referer" '
  '"$http_user_agent"';

формат лога можно укоротить до одного $remote_addr, но я оставил всё, чтобы потом можно было легко и подробно смотреть что-откуда-куда

\etc\nginx\sites-all\ДОМЕН.КОМ.conf

server {
    server_name ДОМЕН.КОМ;
...

    location / {
        index index.php index.html index.htm;
        if ($request ~*

"member.php|administrator/index.php|signup.php|join.php|register.php|submit.php|login.php|show=add|action=register|index.php?option=|wp-login.php|install.php|admin-ajax.php|dompdf.php|ucp.php|cgi-bin|.asp|.cgi|.dll|.exe|.pl|nyet.gif|nyet.html|adserver|appserver|datenbank|file:|/horde|myadmin|mysql|mysql-admin|mysqladmin|mysqlmanager|padmin|php-my-admin|phpmanager|/pma/|/rms/|roundcube|sqlmanager|sqlweb|w00tw00t|/wbb|webadmin|webdb|webmail|websql|xmlrpc|xmlsrv"

        ) {
            access_log /var/log/nginx/deny.log main_post;
            return 444;
        }
        if ( $http_user_agent ~    
    "BLEXBot|wget|Wget|Morfeus|Toata|MJ12bot|QuerySeekerSpider|JikeSpider|proximic|Sosospider|aesop_com_spiderman|alexibot|backweb|batchftp|bigfoot|black.hole|blackwidow|blowfish|botalot|buddy|builtbottough|bullseye|cheesebot|cherrypicker|chinaclaw|collector|copier|copyrightcheck|cosmos|crescent|curl|custo|diibot|disco|dittospyder|dragonfly|drip|easydl|ebingbong|ecatch|eirgrabber|emailcollector|emailsiphon|emailwolf|erocrawler|exabot|eyenetie|filehound|flashget|flunky|frontpage|getright|getweb|go.?zilla|go-ahead-got-it|gotit|grabnet|grafula|harvest|hloader|hmview|httplib|httrack|humanlinks|ilsebot|infonavirobot|infotekies|intelliseek|interget|iria|jennybot|jetcar|joc|justview|jyxobot|kenjin|keyword|larbin|leechftp|lexibot|lftp|libweb|likse|linkscan|linkwalker|lnspiderguy|lwp|magnet|mag-net|markwatch|mata.hari|memo|microsoft.url|midown.tool|miixpc|mirror|missigua|Missigua|mister.pix|moget|mozilla.newt|nameprotect|navroad|backdoorbot|nearsite|net.?vampire|netants|netcraft|netmechanic|netspider|nextgensearchbot|attach|nicerspro|nimblecrawler|npbot|octopus|offline.?explorer|offline.navigator|openfind|outfoxbot|pagegrabber|papa|pavuk|pcbrowser|php.?version.?tracker|pockey|propowerbot|prowebwalker|psbot|pump|queryn|recorder|realdownload|reaper|reget|true_robot|repomonkey|rma|internetseer|sitesnagger|siphon|slysearch|smartdownload|snake|snapbot|snoopy|sogou|spacebison|spankbot|spanner|sqworm|superbot|superhttp|surfbot|asterias|suzuran|szukacz|takeout|teleport|telesoft|the.intraformant|thenomad|tighttwatbot|titan|urldispatcher|turingos|turnitinbot|urly.warning|vacuum|vci|voideye|whacker|libwww-perl|widow|wisenutbot|wwwoffle|xaldon|xenu|zeus|zyborg|anonymouse|emaile|enhancer|go.?is|auto|bandit|clip|copier|sauger|site.quester|whack|craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|grabber|webpictures|Jakarta|User-Agent|libwww|lwp-trivial|PHPCrawl|WEP Search|ISC Systems iRc|Aboundex|360Spider|Java|Cogentbot|BunnySlippers|Cegbfeieh|AIBOT|Demon|Devil|Wondernder|Fooder|Foobot|Kenjin Spider|Density|LinkextractorPro|LWP::Simple|Downloader|NetZIP|Metasearch|WebFetch|WebCopier|Webclipping|WebBandit|WebAuto|WebGo|Web.Image.Collector|WebLeacher|WebmasterWorldForumBot|WebReaper|WebSauger|eXtractor|Webster|WebStripper|WebWhacker|WebZIP|Catall Spider|AcoiRobot|rogerbot|mj12bot|Ahrefsbot|Zite|TweetmemeBot|woriobot|topsy|js-kit|NING|gigabot|YodaoBot|EasouSpider|Baiduspider|ezooms.bot|SeznamBot|discoverybot|uMBot-LN|SimpleCrawler|urllib|sukibot_heritrix|magpie-crawler|GroupHigh|WinHttpRequest"
   
        ) {
            access_log /var/log/nginx/deny.log main_post;
            return 444;
        }

спорный момент в этом списке Java, у юзеров он встречается, но меня сильно долбят боты замаскированные под мобильные телефоны, а там в юзерагенте есть Java.

\etc\fail2ban\jail.conf

добавляем секцию

[nginx-bad-request]
enabled = true
filter  = nginx-bad-request
action  = iptables-multiport[name=nginx-bad-request, port="80,443", protocol=tcp]
          sendmail-whois-lines-nginx[name=nginx-bad-request, dest=ДОМЕН.КОМ@gmail.com, sender=root@ДОМЕН.КОМ, sendername="Fail2Ban"]
logpath = /var/log/nginx/deny.log
bantime  = 3600
findtime = 3600
maxretry = 2

после двух попаданий в течении часа в лог ИП забанится на час
\etc\fail2ban\filter.d\nginx-bad-request.conf   создаём файл такого вида
# fail2ban filter configuration for nginx
# block IP by request with suspicious substring
# если запрошен подозрительный фрагмент в УРЛ то IP в бан на некоторое время

[Definition]

# строка лога
# 11.1111.111.11 [12/Jan/2015:23:50:41 +0200] ДОМЕН.КОМ "GET /cgi-bin/ HTTP/1.0" 444 0 [-] "-" "Opera/5.12"
# user_ip        date                        server_name    request                    ans len POST ref UA

# failregex = ^ \[\S+\] \S+ "\S+ \S+ HTTP/\d+\.\d+" \d+ \d+ \[\S+\] "\S+" "\S+".*$
# в логе все ИП подлежат бану, поэтому можно не парсить весь лог
failregex = ^

ignoreregex =


в файле комментов больше чем кода :)

\etc\fail2ban\action.d\sendmail-whois-lines-nginx.conf

создаём файл такого вида

# Fail2Ban configuration file
#
# Author: F17
#
#

[INCLUDES]

before = sendmail-common.conf

[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
actionstart = printf %%b "Subject: [Fail2Ban] : started on `uname -n`
              Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
              From: <>
              To: \n
              Hi,\n
              The jail has been started successfully.\n
              Regards,\n
              Fail2Ban" | /usr/sbin/sendmail -f

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
actionstop = printf %%b "Subject: [Fail2Ban] : stopped on `uname -n`
             Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
             From: <>
             To: \n
             Hi,\n
             The jail has been stopped.\n
             Regards,\n
             Fail2Ban" | /usr/sbin/sendmail -f

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck =

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = printf %%b "Subject: [Fail2Ban] : banned from `uname -n`
            Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
            From: <>
            To: \n
            Hi,\n
            The IP has just been banned by Fail2Ban after
            attempts against .\n\n
            Lines containing IP: in \n
            `grep -E '(^|[^0-9])([^0-9]|$)' `\n\n
            Here is more information about :\n
            `/usr/bin/whois || echo missing whois program`\n\n
            Regards,\n
            Fail2Ban" | /usr/sbin/sendmail -f

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban =

[Init]

# Default name of the chain
#
name = default

# Path to the log files which contain relevant lines for the abuser IP
#
logpath = /var/log/nginx/deny.log


Далее перезапускаемся

# service nginx restart
# service fail2ban restart

И первое время внимательно читаем логи того, что забанилось и того, что не забанилось и корректируем фильтры.

Внимательно смотрите на то, что копируете отсюда, потому что блоггер любит портить кавычки или скобки. Вордпресса у меня нет, если у вас есть, то конфиг нужно править :)

Это не защита от ДДОСа или флуда. Это разгрузка сервера от внешних дураков.

Всё вы делаете на свой страх и ужас. Я это тестирую всего два дня, результат меня радует, ЛА уменьшилось в два раза, примерно с 4 до 2.

UPDATE
Точки в регулярке нужно экранировать, правильно так

"member\.php|administrator/index\.php|signup\.php|join\.php|register\.php|submit\.php|login\.php|show=add|action=register|index\.php?option=|wp-login\.php|install\.php|admin-ajax\.php|dompdf\.php|ucp\.php|cgi-bin|\.asp|\.cgi|\.dll|\.exe|\.pl|nyet\.gif|nyet\.html|adserver|appserver|datenbank|file:|/horde|myadmin|mysql|mysql-admin|mysqladmin|mysqlmanager|padmin|php-my-admin|phpmanager|/pma/|/rms/|roundcube|sqlmanager|sqlweb|w00tw00t|/wbb|webadmin|webdb|webmail|websql|xmlrpc|xmlsrv"

UPDATE 2
Поскольку будет огромное количество писем о забаненых ИП, то нужно переключить action c sendmail-whois-lines-nginx на sendmail-buffered-nginx. Число строк я поставил 10, но видимо нужно больше :). Там всё просто, если будет нужно - выложу свой вариант.


И да, Ceterum censeo Moskva esse delendam! 



Комментариев нет: