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, пусть даже и теоретически, могут вызвать проблемы при работе приложения.
Спасибо за статью!
Блин. Комментарий отправляется по Enter-у. Неудобно.
Если вы хотели перенос строки
то тут к сожалению так не получится :) . Пожалуйста, рад что понравилось.
Теперь меня ещё и WAF блокирует:) У меня такой вопрос: пользовались ли Transformation Functions? Смотрю в их сторону для обработки base64-encoded параметров, интересно, какие там грабли есть.
конкретно этой, нет у меня пока нет на ресурсах параметров, которые идут в base64 и их надо контролировать. различными urldecode, utf8tounicode -да, проблем не заметил. На предмет наличия проблем с base64decode посмотрите ветку в гите, возможно там отписывались те кто пользовался и с чем-то сталкивался. эта директива достаточно свежая, но не думаю что она должна вызывать большие трудности, я так предполагаю, что разработчики просто подключили библиотеку, которая вызывается при наличии в правиле этой директивы и производит процедуру преобразования, а дальше обрабатывает уже декодированый результат по набору правил.
А если кодированный параметр только один? то есть можно ли перед началом работы правил на параметры X и Y навесить urldecode/base64decodeExt/etc, а потом проверить всем CoreRuleSet-ом ? второй день читаю доки, не могу понять, то ли лыжи не едут, то ли я.
Добрый день. Судя по тому что base64Decode и base64DecodeExt(в отличии от первой позволяет игнорировать не корректные символы, актуально вроде как только для пыха) относятся к Transformation functions, то есть могут быть использованы только для конкретного Rule или цепочки правил. Наследование на остальные правила, без указания в этих правилах этой функции с помощью их вызова типа t:base64Decode, не осуществляется. В целом, мое общение с разрабами помогло мне выяснить одно и самое главное, что весь запрос разбирается на составные части еще до, анализа набором правил разбитых на так называемые Phase 1, 2, 3, 4 и 5 (они же 1- request headers, 2 -request body, 3 — response headers, 4 — response body, 5- logging). И этот набор является неизменным, нет возможности навесить на данные из этого набора не которой метрики и отслеживать ее на протяжении проверки для применения по нему заданной функции трансформации. И если urldecode присутствует как функция трансформации почти во всех правилах. так как не составляет труда определить требуется ее применить или нет. То c base64 не все так однозначно, собственно они сами об этом говорят https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/369. Для понимания как и что работает, рекомендую все таки пользоваться их кратким маном, в целом многие вещи с примерами и достаточно понятны — https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#base64DecodeExt . Ну, а если что, пишите :)