fail2ban охраняет apache (часть «следующая»)…

В прошлой заметке, посвященной fail2ban, я описал пару фильтров, используемых мной для предотвращения «вражеских» происков, направленных против моего apache. Работало все это отлично, и вопросов не возникало. И дальше бы работало, если бы меня не потянуло на разборки с Chillispot. Дело в том, что в описанных мной конфигурациях fail2ban блокирование нежелательного доступа осуществляется при помощи shorewall. А его-то я как раз и поломал, ковыряясь с Chillispot. Точнее, не поломал, а отключил, так как для работы Chillispot требуется загрузка своего собственного скрипта с правилами для iptables, который «множит на ноль» всю работу shorewall

Чтож, iptables, так iptables. Нам-то какая разница!? Нужно всего-лишь заставить fail2ban тоже использовать iptables при блокировании доступа. Для этого залез я в файл /etc/fail2ban/jail.conf и настройки «тюрем» своих поисправлял следующим образом:

[apache-shorewall]

enabled  = true
filter   = apache-noscript
action   = iptables[name=httpd, port=http, protocol=tcp]
logpath  = /var/log/httpd/error_log
maxretry = 2

И второй «тюрьме» тоже:

[apache-overflow]
enabled	= true
filter	= apache-overflows
action   = iptables[name=httpd, port=http, protocol=tcp]
logpath	= /var/log/httpd/error_log
maxretry = 1

Изменения по сравнению с предыдущим вариантом, описанным мной ранее, для наглядности я выделил красным цветом. Также, если сравнить с предыдущими вариантами, я не стал писать строку со вторым «действием» (action) — отправку письма администратору (mail-whois или sendmail). Ему (мне) и так писем достаточно… Названия самих «тюрем» (те, что в указанных примерах написаны в квадратных скобках) я менять не стал. Они все равно ни на что не влияют, только лишь в лог пишутся.

После внесения указанных изменений перезапустил fail2ban командой:

fail2ban-client reload

И все! Кстати, есть еще одно отличие у данного варианта блокирования по сравнению с shorewall, описанным ранее: iptables блокирует только порт apache

Ну «Secure», так «secure» (часть 3 — fail2ban охраняет apache)

В прошлых моих записях с заголовком «Ну «Secure», так «secure» я защищался от попыток постороннего входа в мой «сервер» по ssh. Но, это ведь не единственный порт моего «сервера», который открыт наружу. Раз уж у меня установлен веб-сайт, то доступ к нему извне, естественно, тоже есть. И вот теперь заглянем-ка в файл протокола ошибок apache (/var/log/httpd/error_log):

[Sat Jan 31 12:05:49 2009] [error] [client 89.18.176.83] File does not exist: /var/www/html/bin
[Sat Jan 31 12:05:50 2009] [error] [client 89.18.176.83] File does not exist: /var/www/html/mail
[Sat Jan 31 12:05:52 2009] [error] [client 89.18.176.83] File does not exist: /var/www/html/webmail
[Sat Jan 31 12:05:53 2009] [error] [client 89.18.176.83] File does not exist: /var/www/html/roundcube
[Sat Jan 31 12:05:58 2009] [error] [client 89.18.176.83] File does not exist: /var/www/html/rc

Насколько я понимаю, данные строки лога показывают, что «некто» пытается найти в моем сервере «нечто». Не знаю, можете называть это паранойей, но мне это очень не нравится! А вдруг найдет? Или вот еще, к примеру, строка из лога:

[Mon Jan 26 22:19:46 2009] [error] [client 213.21.37.175] script '/var/www/html/azenv.php' not found or unable to stat

Может это самый лучший и самый полезный в мире скрипт, а может быть и нет. Как по мне, так лучше не надо!

Итак, решено — будем защищаться. fail2ban у меня уже установлен — ssh защищает. Но это далеко не единственная возможность программы. Просто по умолчанию сразу после установки в ней включен единственный фильтр — sshd.conf. Вернемся к сути программы fail2ban. Она постоянно анализирует файлы протоколов работы служб компьютера, пытаясь найти в них сообщения об ошибках, соответствующие установленным шаблонам. Если условие совпадает, программа выполняет указанное действие. Условия-шаблоны прописываются в файлах фильтров, расположенных в папке /etc/fail2ban/filter.d. Возможные действия представлены файлами, находящимися в папке /etc/fail2ban/action.d. Управление «включением» и «выключением» фильтров, а также выбор последующих «действий» осуществляется в файле настроек /etc/fail2ban/jail.conf. Борьбу за безопасность apache я начал с поиска подходящего фильтра в папке /etc/fail2ban/filter.d. На первый взгляд мне подошел файл фильтра apache-noscript.conf. Его я поначалу и задействовал (об этом ниже). Однако, впоследствии, сопоставляя файл протокола ошибок apache и файл протокола работы fail2ban, я заметил, что далеко не все сообщения об ошибках приводят к бану вызвавших их посетителей. Утверждать, что программа не работает, было бы неправдой — на часть ошибок она все-таки реагировала. Следовательно, «что-то не то» с шаблонами. Отличным подспорьем в «разборках» с шаблонами является программа fail2ban-regex, устанавливаемая на компьютер вместе с fail2ban. Программа позволяет проанализировать указанный лог (или просто текстовую строку) на предмет нахождения соответствий шаблону из файла фильтра (или просто текстовой строке). Именно этим я и занялся. Взял лог, взял фильтр и «скормил» их програмке — ввел в консоли команду:

fail2ban-regex /var/log/httpd/error_log apache-noscript.conf

Первый ответ, о том, что найдено аж 10 совпадений меня очень развеселил.  «Невооруженным глазом» было видно, что в логе их гораздо больше… И начал я подбирать шаблон, попутно проверяя его эффективность все той же приведенной выше командой. Число совпадений росло, сначала три сотни, потом больше тысячи, финальный результат был равен 1706. Я решил, что пока хватит, а дальше посмотрим. Теперь о произведенных мной изменениях. Изначально в файле фильтра apache-noscript.conf строка шаблона сообщения об ошибке выглядела так:

failregex = [[]client <HOST>[]] (File does not exist|script not found or unable to stat): .*(\.php|\.asp|\.exe|\.pl)

Результат, который в конце концов устроил лично меня, выглядит так:

failregex = [[]client <HOST>[]] (File does not exist|Invalid URI in request|.* not found or unable to stat)

В чем суть моих изменений? Во первых, оригинальная строка шаблона предполагает, что в логе сообщение об ошибке должно содержать что-либо из «.php», «.asp», «.exe» или «.pl». Если же в строке такого нет, шаблон не срабатывает. Но даже в той «нарезке» лога apache, что я привел выше мы видим, что нет там никаких «.php», «.asp», «.exe» или «.pl». Следовательно фильтр не сработает. По этому, окончание шаблона — (\.php|\.asp|\.exe|\.pl) — я попросту выкинул.

Ну и во вторых, та часть шаблона, которая вылавливает неправильные скрипты. В оригинале она хочет, чтобы в логе был такой текст «script not found or unable to stat» (одним непрерывным куском!!!). Но, посмотрев в свои логи я увидел, что зачастую там текст отформатирован иначе, например так: «script ‘/var/www/html/pt.php’ not found or unable to stat». Следовательно этот фильтр тоже не срабатывал бы. Пришлось его заменить на «.* not found or unable to stat«. В данном случае «.*» обозначает «любой текст». После этого фильтр начал срабатывать на сообщения об ошибках о запуске несуществующих скриптов.

 

Ну и вкратце о том, как я подключал фильтр. В файле настроек /etc/fail2ban/jail.conf я нашел раздел:

[apache-shorewall]

enabled  = false
filter   = apache-noscript
action   = shorewall
           sendmail[name=Postfix, dest=you@mail.com]
logpath  = /var/log/apache2/error_log

И изменил его следующим образом:

[apache-shorewall]

enabled  = true
filter   = apache-noscript
action   = shorewall
           mail-whois[name=Apache, dest=dmitry@my-svr]
logpath  = /var/log/httpd/error_log
maxretry = 2

Таким образом я:

  • включил (enabled = true)…
  • выбранный фильтр (filter = apache-noscript)…
  • на анализ файла протокола (logpath = /var/log/httpd/error_log)…
  • и при возникновении 2 ошибок (maxretry = 2)…
  • доступ блокируется при помощи файервола (action = shorewall).

Вот и все…

P.S.
Не вышло «все», однако… 21 марта с одного IP такой «вал валил», что я решил предпринять что-то. И нашел еще один фильтр — apache-overflows.conf, который вроде как очень подходил моим потребностям. Судите сами, вот кусок лога apache:

[Sat Mar 21 17:19:35 2009] [error] [client 221.223.93.132] Invalid method in request \xf0\xaf\xa0_\x98\x1b\x9fi\xe2\x84\xca\xc8\xca\xfa\xabA\xb4f\xe0+\xf3\x96>S\x90\x90\xc1D\x80\xc2\x11\xe17\xcc\x91\x97
[Sat Mar 21 17:20:04 2009] [error] [client 221.223.93.132] Invalid URI in request \xfb%\xd2\ba\xf5\x84\x9c'\x0c\xbc\xf4|\xffu\x10?\xf2\x96\xee\xda\x9d\xe9\x9f\xb0\x15\xc9\xe9nd
[Sat Mar 21 17:20:43 2009] [error] [client 221.223.93.132] request failed: error reading the headers

А вот (но, правда, уже немножко подкорректированный мной) фильтр:

# Notes.:  Regexp to catch Apache overflow attempts.
# Values:  TEXT
#
failregex = [[]client []] (Invalid method in request|Invalid URI in request|request failed: URI too long|request failed: error reading the headers|erroneous characters after protocol string).*

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

Пришлось и его включать. С поправкой на тот факт, что мне показалось, что это была именно атака, рубить доступ я решил с первой же попытки. Для этого в файл /etc/fail2ban/jail.conf я добавил следующие строки:

[apache-overflow]
enabled	= true
filter	= apache-overflows
action	= shorewall
logpath	= /var/log/httpd/error_log
maxretry = 1

После этого перезапустил fail2ban командой:

fail2ban-client reload

И вот теперь сижу и жду новых поводов для добавления новых фильтров…

Еще про fail2ban

Ну «Secure», так «secure» (часть 2)

В прошлой заметке я уже описал, как боролся с «подбирателями паролей» на моем ssh-демоне. В принципе, я считаю, что принятых мер достаточно для защиты моего сервера (да и кому он надо-то?!). Но, с другой стороны, тысячи строк с сообщением об ошибке в логе авторизации просто «напрягают зрение понапрасну». И вот, просматривая сайт с новостями программного обеспечения, я наткнулся на название программы, которое меня заинтересовало — «Fail2Ban«. Открыл у себя «Центр управления Mandriva Linux», в нем выбрал «Управление программами» и ввел имя программы в поле «Поиск». «Есть у нас такая программа» — сказал поиск. Поставил «птичку», установил. Чем заинтересовала-то меня данная программа? Вот что про нее написано;

Fail2Ban scans log files like /var/log/secure and bans IP that makes too many password failures. It updates firewall rules to reject the IP address. These rules can be defined by the user. Fail2Ban can read multiple log files including sshd or Apache web server logs.

А если вкратце и по русски, программа сканирует логи и динамически меняет правила файервола, запрещая доступ тем IP, с которых происходит слишком много НЕУДАЧНЫХ попыток авторизации (читай, «происходит подбор пароля»)!!! Вот и все!

Остается лишь в качестве подтверждения эффективности программы процитировать два лога. Первый — протокол авторизации в системе (файл /var/log/auth.log):

Jul 25 20:12:31 smb-svr sshd[26144]: Invalid user guest from 61.168.222.170
Jul 25 20:12:31 smb-svr sshd[26144]: error: Could not get shadow information for NOUSER
Jul 25 20:12:31 smb-svr sshd[26144]: Failed password for invalid user guest from 61.168.222.170 port 1652 ssh2
Jul 25 20:12:36 smb-svr sshd[26147]: Invalid user guest from 61.168.222.170
Jul 25 20:12:36 smb-svr sshd[26147]: error: Could not get shadow information for NOUSER
Jul 25 20:12:36 smb-svr sshd[26147]: Failed password for invalid user guest from 61.168.222.170 port 2597 ssh2
Jul 25 20:12:42 smb-svr sshd[26149]: Invalid user guest from 61.168.222.170
Jul 25 20:12:42 smb-svr sshd[26149]: error: Could not get shadow information for NOUSER
Jul 25 20:12:42 smb-svr sshd[26149]: Failed password for invalid user guest from 61.168.222.170 port 3700 ssh2

А второй — протокол работы самой программы (файл /var/log/fail2ban.log):

2008-07-25 20:12:43,045 fail2ban.actions: WARNING [ssh-iptables] Ban 61.168.222.170
2008-07-25 20:22:43,414 fail2ban.actions: WARNING [ssh-iptables] Unban 61.168.222.170

Для «полного понимания» добавлю лишь, что по умолчанию программа:

  • запрещает доступ с IP-адреса после трех неверных попыток ввода пароля;
  • блокирует доступ на 600 секунд.

Первое прекрасно видно при сравнении времени третьей попытки из первой «цитаты» со временем включения файервола во второй «цитате». Второе легко заметить, сравнив во второй «цитате» время включения и выключения блокирования адреса. При желании Вы можете изменить те значения настроек, которые Вас не устраивают , самостоятельно отредактировав файлы в папке /etc/fail2ban.

…С тех пор у меня нет в логах авторизации многотысячных записей «Failed password for invalid user...» Чего и вам желаю!,,,

ЗЫ. Балуясь на днях (зкспериментируя) с авторизацией в ssh, заполучил бан самого себя. «Сервер» дома, я на работе, а дела-то не ждут! Пришлось себя срочно «разрешать»… Спас Webmin. У него в разделе «Прочее» есть пункт «Командная оболочка (shell)» (командная строка). Вот в ней-то я и запустил команду:

fail2ban-client status

Сервер fail2ban ответил, что запущен следующий фильтр (Jail): ssh-iptables. Чтобы остановить его, ввел команду:

fail2ban-client stop ssh-iptables

И напоследок, чтобы на будущее меня ни в коем случае не банило, прописал свой рабочий адрес в файл /etc/fail2ban/jail.conf в строке:

ignoreip = 127.0.0.1 XXX.XXX.XXX.XXX

(адреса, когда их несколько, разделяются пробелами)…

Ну «Secure», так «Secure»…

«Сервер» мой домашний — это просто системный блок, лежащий на холодильнике. Ни монитора, ни клавиатуры с мышью к нему не подключено. Все управление своим «сервером» я осуществляю дистанционно по сети. Для этого я установил и настроил службу удаленного доступа — «сервер-NX». Процедура установки и настройки уже описана мной тут. NX-сервер в своей работе использует механизмы службы SSH (secure shell), и поэтому, у сервера запущен демон SSH, который постоянно ожидает соединений на 22 порту. Естественно, с этой же целью в моем ADSL-маршрутизаторе настроен «port forvarding» 22-го порта на мой «сервер» (я им не только из дома, но и с работы «порулить» могу). А с другой стороны «бог даровал» народу всевозможные программы «сканеров портов». И как следствие, периодически кто-то пытается подобрать к моему серверу имя пользователя и пароль, о чем «сервер» мой все четко пишет в файл протокола аутентификации /var/log/auth.log :

Failed password for invalid user bin from XXX.XXX.XXX.XXX port 52100 ssh2
Failed password for invalid user daemon from XXX.XXX.XXX.XXX4.32.126 port 52567 ssh2
Failed password for invalid user sync from XXX.XXX.XXX.XXX port 52610 ssh2
Failed password for invalid user shutdown from XXX.XXX.XXX.XXX port 52676 ssh2
Failed password for invalid user halt from XXX.XXX.XXX.XXX port 52728 ssh2
Failed password for invalid user uucp from XXX.XXX.XXX.XXX port 52777 ssh2
Failed password for invalid user smmsp from XXX.XXX.XXX.XXX port 53021 ssh2

Причем, число подобных строк в протоколе может достигать нескольких тысяч за час (неймется им!). «Хорошая» штука — сканер портов. Без нее у «гражданина-хакера» уже все пальцы «в дым стерлись бы»!.. А так — сиди, чай попивай!..

Получится ли у «хакера» войти в мой «сервер» или нет — это еще вопрос. Но, как говорится, «береженого бог бережет». Чтож, будем защищаться! В принципе, у SSH существует сравнительно простой способ напрочь забыть о таких «взломщиках». Для этого нужно просто настроить доступ к серверу по SSH-ключу, и полностью отключить возможность входа по паролю. Ключ может быть длинный, например, 2048 байт, и подобрать его будет, мягко говоря, затруднительно. Как настроить службу SSH, подробно описано на вот этой странице, и дублировать тут ее целиком я не вижу смысла. Если вкратце, то лично я, руководствуясь информацией с этой страницы, находясь в консоли той клиентской машины и с правами того пользователя, для которых настраиваем доступ к серверу по ключу, выполнил всего две команды. Сначала я выполнил следующее:

ssh-keygen -t rsa -b 2048

Данная команда сначала спрашивает имя файла ключа (используем значения, предложенные по умолчанию), потом предлагает ввести дополнительный пароль (passphrase) для ключа (это повышает безопасность, но потом пароль нужно будет вводить все время), и затем создает пару ключей (приватный и публичный) в папке $HOME/.ssh/ на клиентской машине. Именно эти ключи и будут в дальнейшем использоваться вместо пароля при идентификации пользователя на сервере. После этого, перейдя в папку $HOME/.ssh/ я выполнил вторую команду:

ssh-copy-id -i id_rsa.pub dmitry@myserver

Эта команда сперва спрашивает пароль пользователя на сервере, а затем копирует публичный ключ (файл id_rsa.pub) в папку указанного пользователя на указанный сервер (естественно, вместо «dmitry» Вы подставляете свое имя пользователя, а вместо «myserver» имя своего сервера). После этого проверяем возможность беспарольного входа — в консоли клиентской машины вводим команду:

ssh dmitry@myserver

Результат успешного выполнения данной команды — вы входите в консоль сервера, не вводя никаких паролей. После этого можно в SSH отключить возможность доступа по паролю — в файле /etc/ssh/sshd_config сервера строку «PasswordAuthentication yes» заменить на «PasswordAuthentication no«. Учтите, что после внесения изменений в конфигурацию сервера, его нужно перезапустить. После этого сканеры портов не смогут подбирать пароль к Вашему компьютеру по той простой причине, что доступ по паролю будет отключен!

И все было бы хорошо, если бы не одно «но». После таких манипуляций становится невозможным вход в сервер при помощи NX! Об этом, кстати, четко сказано в документации к NX-серверу — «работа службы в случае запрета SSH-доступа по паролю невозможна». Читаем мы, правда, обычно уже «потом»… Честно говоря, поначалу я был удивлен. Еще при настройке сервера NX я видел, что им при аутентификации используется не пароль, а публичный ключ. Понимание того, «почему нельзя», пришло после прочтения все того же файла протокола аутентификации в начале NX-сессии. В нем мы видим следующие три строки:

Accepted publickey for nx from 192.168.1.15 port 3640 ssh2
Accepted password for dmitry from 127.0.0.1 port 45410 ssh2
Accepted publickey for dmitry from 127.0.0.1 port 45411 ssh2

Как мы видим в приведенном фрагменте лога, ИЗВНЕ в сервер входит не пользователь «dmitry«, а пользователь «nx«. Причем, входит не по паролю, а по ключу (тому самому, который и «длинный», и «трудно подбираемый»). А вот имя пользователя (в моем случае — «dmitry«) и пароль (как следует из второй приведенной строки), используется уже для запуска сессии только ВНУТРИ сервера.

Что нам это дает? Во-первых, понимание того, что доступ по паролю все-таки нужно включить обратно. А то «кина не будет»!… Поэтому, в файле /etc/ssh/sshd_config сервера снова возвращаем на место строку «PasswordAuthentication yes» (аутентификация по паролю разрешена). Не забываем при этом перезапустить сервер. Выходит, что мы вернулись к тому, с чего начинали! Но, у SSH есть еще одна возможность — управление доступом пользователей. Причем, с учетом адреса(ов) машин(ы), с которой(ых) данный пользователь пытается получить доступ к серверу. Каким образом мы можем это использовать? Возьмем всё тот же файл конфигурации демона SSH (/etc/ssh/sshd_config), и впишем в него следующие строки:

AllowUsers nx
AllowUsers dmitry@127.0.0.1

А теперь о том, что это строки обозначают. И начнем со второй строки. В ней указано, что пользователю «dmitry» разрешен вход в сервер ТОЛЬКО ЛИШЬ С ВНУТРЕННЕГО АДРЕСА «127.0.0.1» (того, что указан после «собаки»). И ни с каких других! Кстати, вместо конкретного адреса может быть указан шаблон, например, «192.168.0.*» (вся локальная сеть). А теперь вернемся к первой строке — она разрешает доступ к серверу пользователю «nx«. Причем, так как в ней нет никаких указаний адресов после «собаки», то данному пользователю доступ разрешен с ЛЮБОГО адреса. И еще один нюанс — сам факт наличия в конфигурации SSH-сервера пользователей, разрешенных директивой «AllowUsers«, обозначает, что всем другим доступ к серверу ЗАПРЕЩЕН!

Если быть более точным, то директив, управляющих доступом по SSH четыре: DenyUsers (запрещенные пользователи), AllowUsers (разрешенные пользователи), DenyGroups (запрещенные группы), и AllowGroups (разрешенные группы). До тех пор, пока в конфигурации демона SSH нет ни одной из этих директив, доступ разрешен ВСЕМ. Наличие ЛЮБОЙ из указанных директив будет ограничивать доступ соответствующим образом. В случае использования НЕСКОЛЬКИХ (или всех) указанных директив порядок проверки будет следующим: DenyUsers, AllowUsers, DenyGroups, и наконец AllowGroups.

В итоге, указавши двух пользователей как приведено выше, мы получили следующее — ИЗВНЕ в наш сервер может войти только лишь один пользователь «nx«. Войдя в сервер, пользователь «nx» запускает уже ЛОКАЛЬНУЮ (с адреса 127.0.0.1) сессию пользователя «dmitry«, который хоть и аутентифицируется по паролю, но уже ВНУТРИ сервера …

Таким образом, сейчас тому, кто захочет войти в мой «сервер» понадобится всего лишь подобрать публичный ключ. Тот, который длинной 2048 бит… Кому не лень, пусть подбирает!

ЗЫ. Если же для «себя любимого» (или другого пользователя) нужно оставить и возможность входа в Secure Shell (SSH), то во все тот же файл конфигурации демона SSH (/etc/ssh/sshd_config) нужно вписать соответствующие «разрешающие» строки с указанием адреса(ов) компьютера(ов), с которых необходимо разрешить доступ. Например вот так:

AllowUsers dmitry@91.121.15.100

(разрешает доступ пользователю «dmitry» с компьютера с адресом «91.121.15.100«). Или, например, вот так для всей подсети (внутренней):

AllowUsers dmitry@192.168.0.*