Заметки об Apache, часть 6: Простая защита от ДДоС/брутфорса средствами ModSecurity

Date March 27th, 2013 Author Vitaly Agapov

Попробуй хотя бы… Сыграем мир в четыре руки?

Г.Л.Олди «Восставшие из рая»

Года, эдак, три назад я уже постил здесь статейку "mod_security2 для Apache", касающуюся использования модуля ModSecurity. Она и сейчас вполне занятна, полезна и самодостаточна. И там даже был пример на нашу сегодняшнюю тему, но я хотел бы эту самую тему углубить и рассмотреть более подробно. Посмотрим, как можно защититься от перебора паролей на сайте или даже обеспечить простенькую (это ключевое слово, так как от забивания полосы канала это не спасёт) защиту от DDoS. Посмотрим, как в ModSecurity можно работать со счётчиками и реализовывать на этих счётчиках сценарии защиты.

Итак, мы предполагаем, что некоторые антисоциальные элементы могут начать доставлять нам неудобства, заваливая сайт некоторыми запросами на логин или, например, на некоторые тяжёлые страницы, нагружающие бэкенд. Давайте их банить.

Установка ModSecurity

В старой статье я не останавливался на установке. А тут остановлюсь, но только для Ubuntu.

sudo apt-get install libapache2-modsecurity

Сделает всё необходимое, а основной конфиг модуля положит в /etc/apache2/mods-enabled/mod-security.conf. В этом конфиге будет строчка

Include “/etc/modsecurity/*.conf”

И именно здесь можно будет хранить свои персональные настройки логики mod-security. Кстати, их можно вписывать и в другие контексты, например VirtualHost, Location, LocationMatch, Directory…

Рабочий пример

Создаём в /etc/modsecurity/ новый конфиг:

SecRuleEngine On
SecRequestBodyAccess Off
SecRule REQUEST_BASENAME "login.htm" "phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.requests=+1,expirevar:ip.requests=2"
SecRule ip:requests "@ge 3" "phase:1,pass,nolog,setvar:ip.block=1,expirevar:ip.block=15,setvar:ip.blocks=+1,expirevar:ip.blocks=3600"
SecRule ip:blocks "@ge 5" "phase:1,deny,log,logdata:'req/sec: %{ip.requests}, blocks: %{ip.blocks}',status:403"
SecRule ip:block "@eq 1" "phase:1,deny,log,logdata:'req/sec: %{ip.requests}, blocks: %{ip.blocks}',status:403"
SecAuditEngine RelevantOnly
SecAuditLogParts ABFHZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log

А теперь смотрим построчно, что тут такое.

SecRuleEngine On

Включает обработку правил ModSecurity. Вместо On можно указать DetectionOnly, отчего mod-security будет только обнаруживать нужные транзакции и логировать их, не вмешиваясь в обработку.

SecRequestBodyAccess Off

Выключает сохранение и обработку тел запросов внутри ModSecurity. Включить её нужно в том случае, если в логике требуется анализ содержимого запроса (в переменной REQUEST_BODY).

SecRule

В целом использование этой директивы имеет вид: SecRule Переменная Оператор Действия. В первой строке

SecRule REQUEST_BASENAME “login.htm” “phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.requests=+1,expirevar:ip.requests=2″

Сравнивается имя запрашиваемого файла и интересующая нас страница login.htm. При совпадении разбирается строка с действиями:

phase:1 – выполнение действия в первой фазе обработки (то есть на этапе обработки заголовков сообщения).
nolog – не логировать совпадение (на этом этапе оно нам пока не интересно, логировать будем потом, когда вычислим злоумышленников).
pass – пока что пропускаем транзакцию до следующего правила
initcol:ip=%{REMOTE_ADDR} – создаём новое хранилище с названием ip с ключом в виде REMOTE_ADDR, то есть ip-адреса отправителя. Если хранилище уже существует, то загружаем его в память.
setvar:ip.requests=+1 – в хранилище ip увеличиваем переменную requests на единицу.
expirevar:ip.requests=2 – устанавливаем обнуление переменной через две секунды. Этак команда всегда должна идти рядом с setvar.

Следующая строка:

SecRule ip:requests “@ge 3″ “phase:1,pass,nolog,setvar:ip.block=1,expirevar:ip.block=15,setvar:ip.blocks=+1,expirevar:ip.blocks=3600″

В случае, если значение переменной requests хранилища ip превышает 3, то устанавливается в единицу новая переменная ip.block, обнуляющаяся через 15 секунд и увеличивается на единицу переменная ip.blocks, обнуляющаяся через час.

SecRule ip:blocks “@ge 5″ “phase:1,deny,log,logdata:’req/sec: %{ip.requests}, blocks: %{ip.blocks}’,status:403″

Если переменная ip:blocks превысила 5, то выполняются действия:

deny – транзакция прерывается.
log – в аудит-лог отправляется сообщение.
logdata:’req/sec: %{ip.requests}, blocks: %{ip.blocks}’ – формат строчки, которая окажется в логе.
status:403 – код возврата – 403 Forbidden.

И следующая строчка делает то же самое, но при переменной ip:block, равной единице.

SecAuditEngine RelevantOnly

Логировать только транзакции, возвращающие ошибки.

SecAuditLogParts ABFHZ

Тут мы указываем, что хотим видеть в своём аудит-логе. Каждая буква означает свою часть лога. А – обязательный log header, B – заголовки, F – заголовки ответа, H – log trailer, обязательное обозначение конца записи.
Другие возможные параметры: C или I – тело запроса, E – тело ответа.

SecAuditLogType Serial

Включаем последовательную запись аудит-лога.

SecAuditLog /var/log/apache2/modsec_audit.log

Указываем путь к аудит-логу.

В результате ModSecurity будет считать количество обращений к login.htm (в том числе и по https) с каждого ip-адреса. Если придут 4 запроса с интервалами менее 2 секунд, то транзакции будут заблокированы на 15 секунд. Если после этого придут ещё 5 запросов с интервалами не более 15 секунд, то ip отправится в бан на 3600 секунд.

Что ещё мы можем сделать

Мы можем производить декремент переменных (вместо их обнуления, как в примере выше). Например, уменьшаем переменную ip.blocks на 2 через каждые 60 секунд:

SecRule ip:requests "@ge 3" "phase:1,pass,nolog,setvar:ip.blocks=+1,deprecatevar:ip.blocks=2/60"

Мы можем обрывать транзакции, не отвечая на них кодом ошибки (да ещё оставляя читаемый текст в аудит-логе):

SecRule ip:requests "@ge 3" "phase:1,log,drop,msg:'Brute Force'

Мы можем некоторые запросы пропускать безусловно, например, по ip:

SecRule REMOTE_ADDR "^192\.168\.1\.1$" phase:1,nolog,allow

Мы можем добавлять свой текст к ответам (append добавляет текст в конце, prepend – в начале):

SecContentInjection On
SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,pass,append:'<span>Hello</span>'"

Можно делать цепочки из правил, когда последующие правила проверяются только при выполнении предыдущих. Для этого служит действие chain:

SecRule REQUEST_METHOD ^POST$ chain,t:none
SecRule REQUEST_HEADER:Content-Length ^$ t:none

Мы можем выполнить любой внешний скрипт по определённым условиям (действие t выполняет разные преобразования):

SecRule ip:requests "@ge 3" "phase:2,t:none,t:lowercase,t:normalisePath,log,exec:/usr/local/apache/bin/test.sh"

Мы можем произвести проксирование или редирект запроса на другой бэкенд или внешний сервер:

SecRule REQUEST_HEADERS:User-Agent "proxyme" log,proxy:http://192.168.1.1:8080/
SecRule REQUEST_HEADERS:User-Agent "redirectme" log,redirect:http://www.redirecthere.com/

Ссылки

А ссылка будет всего одна:

https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual

Tags: ,
Category: Apache | 1 Comment »

Comments

Один комментарий на “Заметки об Apache, часть 6: Простая защита от ДДоС/брутфорса средствами ModSecurity”

  1. agapoff.name | IT блог » Blog Archive » Nginx и ModSecurity

    […] ModSecurity, про который я относительно недавно опять писал статейку. Каково же было моё удивление, тщательно перемешанное […]

Leave a comment

 Comment Form