ModSecurity создан Иваном Ристиком (Ivan Ristic) в 2003 году и представляет собой firewall Web-приложений, который может использоваться как модуль Web-сервера Apache, либо работать в автономном режиме и позволяющий защитить Web-приложения как от известных, так и неизвестных атак.

Мы не будем говорить, о каких то базовых настройках, для этого достаточно прочитать официальную документацию по адресу https://github.com/SpiderLabs/ModSecurity, или обратиться за помощью к специалистам.

Я бы хотели рассказать о работе с WAF, о нюансах и трудностях, с которыми столкнулся уже сейчас. А дальше решать уже вам, готовы вы с чем то мириться и бесплатно получить не самый плохой WAF или все же обратить внимание на более известные, но платные, с меньшим количеством проблем и теоретической возможностью зависти обращение в техническую поддержку  в рамках лицензии и получить, если очень повезет, быстро заплатку.

1. Общие сведения

1.1 Официальный сайт

https://www.modsecurity.org/
На сайте вы можете увидеть информацию о наличии платной версии. На самом деле на платные и бесплатные делятся только наборы правил. Сам исходный код продукта, открыт и бесплатный, актуальная версия, на момент написания статьи 2.9.1(когда то она именовалась 3.0).
https://github.com/SpiderLabs/ModSecurity/releases

Платный набор правил от бесплатного отличается тех. поддержкой. Для платной поддержка осуществляется на основе лицензии. Поддержка по бесплатному набору на основе комментариев в github. Текущая актуальная версия набора правил 2.2.9, готовится к релизу набор правил 3.0 под ядро версии 3.0, сейчас эта версия стала именоваться 2.9.1, часть правил претерпели изменения, появились новые операторы (я нашел два). Я сейчас использую микс набора правил из этих двух веток.
https://github.com/SpiderLabs/owasp-modsecurity-crs

Второе, основное отличие в том, что бесплатный набор содержит правила от основных типов атак, анализ правил натолкнул на мысль, что за основу взяты типы и методы атак, описанные на страницах ресурса OWASP, что собственно логично.
Платные же дополнены правилами закрывающими уязвимости в популярных коммерческих CMS, таких как: Microsoft SharePoint, WordPress, cPanel, osCommerce, Joomla, cPanel, Drupal, vBulletin.

С полным списком сервисов за деньги можно ознакомиться тут:
https://www.modsecurity.org/commercial-rules.html

Дальше, когда мы будем говорить о правилах, как отдельных, так и их группах, будем иметь в виду, только правила из бесплатного набора.

Большая часть политик, реализующих защиту от SQLi, XSS и т.п. строится на основе регулярных выражений, для обработки regexp используется PCRE библиотека, реализующая работу регулярных выражений в стиле Perl (с некоторыми отличиями).

1.2 Изначально ModSecurity разрабатывался только для Аpache, на данный момент он является кросс-платформенными решением и может быть установлен как на Apache, так и на Nginx и IIS.

1.3 У ModSecurity как и у любого WAF(по крайне мере те о которых я слышал, видел, устанавливал и настраивал) есть три основных состояния/режима работы это:
а) отключена обработка запроса правилами
SecRuleEngine Off

б) включена в режиме обучения, режим предназначен для первичной подгонки правил
SecRuleEngine DetectionOnly

в) ну и соответственно боевой режим, когда правила активны и их срабатывание могут вызывать блокировку запросов или ответов от сервера, попавших под условия блокировки(да, он умеет слушать и прогонять по правилам не только REQUEST, но и RESPONSE, прослушивание ответов от сервера с веб приложением нацелено в первую очередь на подавление выводов ошибок).

При чем в рабочем режиме блокировка может происходить на основе одного из двух способов или методов, называйте кому как удобно.

Тут надо заметить, что все правила имеют свой уровень критичности, в большинстве своем во всех правилах с наивысшим уровнем критичности (Critical), в качестве реакции/действия на срабатывание правила происходит запись информации в лог, считаются баллы и применяется блокировка запроса, отдавая в ответ пользователю 404 (по дефолту, можно сменить). Остальные правила с более низким уровнем критичности(но не все), пишут в лог и считают балы, блокировку они не вызывают. Это и есть первый метод/режим блокировки, по уровню критичности, он же используется по умолчанию при установке.

Второй это на основе баллов, которые считают правила, но в случае включения этого режима, блокировка запроса, если она присутствует в этом правиле, не отрабатывает, в переменную вносится информация о правиле, которое сработало, и считаются баллы. После прохождения всех правил, запрос обрабатывается результирующим правилом которое суммирует и вычитает баллы, получает итоговое значение и сравнивает его с пороговым. Если порог достигнут, запрос блокируется (собственно этот режим мы предпочитаем использовать). На мой взгляд это более гибкое решение, уменьшает кол-во ложных блокировок. Тем более что пороговое значение можно менять, по умолчанию 15, стоимость правил по уровню критичности так же можно менять.

Critical — Anomaly Score of 5. Is the highest severity level possible without correlation.  It is normally generated by the web attack rules (40 level files).

Error — Anomaly Score of 4. Is generated mostly from outbound leakage rules (50 level files).

Warning — Anomaly Score of 3. Is generated by malicious client rules (35 level files).

Notice — Anomaly Score of 2. Is generated by the Protocol policy and anomaly files.

Ну вот, с краткой информацией по системе ознакомились, теперь переходим к основному, с чем столкнулся, что работает на мой взгляд не так, а что не так как заявлено в документации.

2. Особенности

2.1 Грабли раз, версия под nginx. Так как на frontend часто используется nginx, то и я поставил на тест исходник под nginx. Хочу оговориться сразу, не все однозначно, могли сказаться на результате, что это было начало общения с ModSecurity, что тестировал  на ядре  2.7.7. Возможно, что ситуация уже давно изменилась в лучшую сторону на ядрах версий 2.9.0 и 2.9.1.

Установка прошла нормально, направил запросы с ресурса на WAF, и все, развлекаемся, POST обрабатывается криво, постоянно идут ошибки с PCRE Limit (лимит на рекурсию), не все, по не понятным причинам попадает в логи. Увеличение лимитов для PCRE до заоблачных значений, как рекомендуют на многих ресурсах в интернете(ресурсы, где эти рекомендации приводились, не имели отношения к проекту данного WAF) не помогает. И тут все-таки решил  просмотреть ветку сообщений с багам для Modsecurity под разные платформы для текущей версии. И как  итог – теперь WAF  живет на Apache.  Через забавную схему USER->Nginx->Apache->WAF->Apache->Nginx->backend.

Так что, уважаемый читатель, изучайте вначале все-таки мануалы, ну или как в данном случае, листайте комментарии и смотрите на баги уже заявленные другими

3. Правила

3.1. Подключение правил для ресурса в ModSecurity. Включение наборов правил на многих сайтах рекомендуют делать так:
Include "/какой-то путь до директории с modsec/modsec/base_rules/*.conf"

Поверьте, это не самый правильный и надежный способ, modsec не выстраивает очередность исполнения правил по уникальному ID каждого правила, он подключит в том порядке, как файлы отсортированы в директории. Если вы хотите точно знать в каком порядке выполняются проверки, делайте так:
Include "/какой-то путь до директории с modsec/modsec/base_rules/modsecurity_crs_20_protocol_violations.conf"
Include "/какой-то путь до директории с modsec/modsec/base_rules/modsecurity_crs_21_protocol_anomalies.conf"
Include "/какой-то путь до директории с modsec/modsec/base_rules/modsecurity_crs_23_request_limits.conf"
Include "/какой-то путь до директории с modsec/modsec/base_rules/modsecurity_crs_30_http_policy.conf"
....

И include результирующего правила, подсчитывающего баллы, должно быть всегда в самом низу конфигурационного файла, после всех правил, как из набора, так и созданных вами. И еще один совет, касательно правил, не вносите изменения в эталонные правила. Используйте директивы позволяющие вносить изменения в данное правило. Не отключайте шаблонное правило комментированием его. Используйте опять же директиву SecRuleRemoveById. Это сохранит ваше время и нервы при обновлении наборов правил, или при включении в защиту еще одного веб ресурса.
Да, уточнение, все эти директивы, в конфигурационном файле должны идти строго ниже include того правила, в которое вы вносите изменение или отключаете его. В противном случае не сработает, a WAF при проверке корректности синтаксиса во время внесения изменений, на это не обращает внимание, и говорит все ОК, изменение принято.

3.2 Самая большая и крупная проблема у ModSecurity это не английские буквы, т.е. все те символы и буквы, которые в  hexadecimal кодировании принимают вид \xXX\xXX (на пример буква ‘я’-\хd1\х8f). WAF игнорирует старший байт \xd1, который ему пытается сказать, что я буква не английского алфавита, следующий байт за мной \x8f это тоже моя часть. ModSecurity рассматривает это как два символа. На безопасность это не влияет, но создает ложные срабатывания, если у вас, на пример в строке поиска не пытаются загнать пол страницы Войны и Мира, то больших хлопот не доставит, просто используйте метод блокировки на основе балльной системы. Так как со стороны разработчиков пока еще нет решения.
https://github.com/SpiderLabs/ModSecurity/issues/708

3.3 Во многих регулярных выражениях политик встречается вот такое \W, что означает «Буквенный или цифровой символ или знак подчёркивания». И не смотря на то, что в описании PCRE библиотеки заявлено, что она осуществляет мультиязычную поддержку, не рассчитывайте что символы не попадающие в стандартную ASCII таблицу тоже будут считать буквенным символом, это не так. Используйте эквивалент этой записи, к примеру, для английского языка, он  выглядит так [^A-Za-z0-9_]. Замените на него и дополните буквами вашего алфавита, но не забывайте про пункт 3.1 при этом.

3.4 Помните в пункте 3.1 упоминали директиву SecRuleRemoveByID? Эта директива отключает использование правила с указанным ID для всех запросов в данном ресурсе. Но документация по ModSecurity указывает что данную директиву можно так же использовать и внутри вашего произвольного правила. В правило встраивается вот такая строчка ctl:ruleRemoveByID, и когда ваше правило отработает, запрос не должен попасть в проверку правила с указанным ID. Данное правило должно  отключиться для этого запроса. Так вот, на ядре 2.7.7 и 2.9.0 — не работает. Если требуется для определенных запросов пропускать обработку рядом правил, а в вашей версии сборки вы еще не проверяли работает или нет. Проще использовать команды позволяющие пропустить определенное кол-во правил следующих за вашим. Ну и соответственно, в этом случае, ваше правило надо располагать над правилом, которое надо проигнорировать.

3.5 В ветке директории экспериментальные правила, есть два набора :
modsecurity_crs_11_dos_protection.conf
modsecurity_crs_11_slow_dos_protection.conf

Не советую включать. Для релиза правил 3.0, изменили их или нет, по отношению к текущему релизу не смотрел. Но в текущем релизе, что на ядре 2.7.7, что на текущем 2.9 вызывают большую задержку в обработке правил и огромное кол-во блокировок запросов.

3.6 В пункте 1.3 мы говорили о директиве SecRuleEngine, и что при директиве Off останавливается обработка правил. Да, это так, но именно правил из базового набора и ваших, если они есть. И если вы для ресурса целиком или для отдельного Location вашего ресурса, применили SecRuleEngine Off. Имейте ввиду, что WAF все равно обрабатывает запрос и если, к примеру, длинна URL или общий размер запроса, превышают установленные значения в файле :
modsecurity_crs_10_setup.conf
WAF выдаст Reject такому запросу.

3.7 JSON, поддержка, точнее корректный парсинг его появился только в ядре 2.9, но при одном маленьком условии, в header должно быть:
Content-Type: application/json
В противном случае, куча false positive

3.8 И еще один момент, обращение к разработчикам еще не создавал по этому вопросу, но обязательно будет создано. Предложение о доработке в следующих версиях – о введении понятия списка кук, которые должны проверяться правилами.
На данный момент проверяются все куки в запросе, кроме тех, для которых явно указано в самом правиле — не проверять.

На тех ресурсах, что сейчас в защите, первое время, пока собирали и анализировали логи в режиме DetectionOnly, наблюдали набор большого кол-во баллов. Что могло означать возможные блокировки, при включении режима защиты. Срабатывали правила для кук, которые прилетали с запросами от пользователя, но не относились к данному ресурсу. Это куки от различных SEO тулбаров, adware и т.п. Сейчас я, в основной группе правил, которые давали false positive, внес изменения, и теперь они проверяют только те куки, которые обрабатываются нашими серверами, а значит и внедрение в которые различного рода injection, пусть даже и теоретически, могут вызвать проблемы при работе приложения.