- Вопрос или проблема
- Ответ или решение
- Ответ на вопрос о ModSecurity, который не блокирует запросы, несмотря на триггер правила и возврат 403
- 1. Фазы обработки правил
- 2. Проверка настроек конфигурации
- 3. Совместимость с Apache и модулями
- 4. Логи и отладка
- 5. Общие улучшения безопасности
- 6. IP и ASN блокировки
- Заключение
Вопрос или проблема
Я усилил защиту нашей установки WHMCS (система выставления счетов на основе PHP) и установил mod_security, чтобы защитить её от более очевидных атак SQL-инъекций, чтобы минимизировать нашу уязвимость в период между тем, как уязвимость становится известной, и тем, когда мы о ней узнаем (в этот момент мы применяем IP ACL или новые правила mod_security по мере необходимости, и устанавливаем патчи, когда они доступны).
Проблема в том, что у меня есть некоторые правила, которые я нашел на WHT, которые на бумаге выглядят хорошо, и когда я их тестирую, mod_security по-видимому выполняет свою работу – злоумышленник перенаправляется на 403, но POST-данные, по-видимому, все еще достигают PHP-скрипта, потому что содержание базы данных изменяется.
PHP работает с suPHP; мне неясно из поисковых запросов в Google, может ли это быть причиной проблем – я не могу представить, что такая конфигурация бывает так уж редка.
На мой взгляд, вероятная причина в том, что, несмотря на то, что mod_security настроен на отклонение, он все еще генерирует промежуточное тело ответа (судя по тому, что он может это залогировать, под типом E) – это, конечно, включает отправку данных, которые я хочу остановить в первую очередь! Однако даже если я установлю SecResponseBodyAccess в Off, это не останавливает отправку данных – и, честно говоря, я бы не ожидал, чтобы правило deny/drop, сработавшее на этапе запроса, предотвратило бы любую попытку создать тело ответа.
Кто-нибудь может прояснить это? Есть ли ошибка в этой версии mod_security (мало вероятно, что я первый, кто это заметил), дефектные ли правила, которые я нашел (возможно), или же просто глупая ошибка где-то в моей конфигурации (более вероятно)?
Это система Debian Squeeze; возможно, релевантные пакеты:
ii apache2 2.2.16-6+squeeze11 Мета-пакет Apache HTTP Server
ii libapache2-mod-suphp 0.7.1-1 Модуль Apache2 для запуска PHP-скриптов с правами владельца
ii libapache2-modsecurity 2.6.6-6~bpo60+1 Укрепление безопасности веб-приложений для Apache
/etc/apache2/mods-enabled/modsecurity.load
LoadFile /usr/lib/libxml2.so.2
LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so
/etc/apache2/mods-enabled/modsecurity.conf
<IfModule security2_module>
# Директория по умолчанию для постоянных данных modsecurity
SecDataDir /var/cache/modsecurity
# Включить все файлы *.conf в /etc/modsecurity.
# Хранение вашей локальной конфигурации в этой директории
# позволит легко обновить ЭТОТ файл и
# упростит вашу жизнь
Include "/etc/modsecurity/*.conf"
</IfModule>
/etc/modsecurity/modsecurity.conf
(в основном без изменений от рекомендуемой конфигурации по умолчанию Debian – за исключением изменения SecRuleEngine DetectionOnly на On)
# -- Инициализация движка правил ----------------------------------------------
# Включить ModSecurity, подключив его ко всем транзакциям. Используйте режим только для обнаружения
# вначале, потому что это минимизирует шансы на нарушение работы после установки.
#
SecRuleEngine On
# -- Обработка тела запроса ---------------------------------------------------
# Позволяет ModSecurity получить доступ к телам запросов. Если вы этого не сделаете, ModSecurity
# не сможет увидеть никакие параметры POST, что открывает большую уязвимость
# для злоумышленников.
#
SecRequestBodyAccess On
# Включить парсер тела запроса XML.
# Инициировать XML-процессор в случае типа содержимого xml
#
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
"phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
# Максимальный размер тела запроса, который мы готовы принимать для буферизации. Если вы поддерживаете
# загрузки файлов, то значение, указанное в первой строке, должно быть таким же большим,
# как и самый большой файл, который вы готовы принять. Второе значение относится
# к размеру данных, за исключением файлов. Вы хотите оставить это значение как
# можно ниже.
#
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
# Хранить до 128 КБ данных тела запроса в памяти. Когда многочастный
# парсер достигает этого предела, он начнет использовать ваш жесткий диск для
# хранения. Это медленно, но неизбежно.
#
SecRequestBodyInMemoryLimit 131072
# Что делать, если размер тела запроса превышает наш установленный лимит.
# Имейте в виду, что эта настройка автоматически будет установлена в ProcessPartial
# когда SecRuleEngine установлен в режим DetectionOnly, чтобы минимизировать
# нарушения при первоначальном развертывании ModSecurity.
#
SecRequestBodyLimitAction Reject
# Убедитесь, что мы правильно обработали тело запроса.
# В качестве правила хорошей практики, когда не удается обработать тело запроса,
# вы должны отклонить запрос (при развертывании в блокирующем режиме)
# или залогировать предупреждение высокой серьезности (при развертывании в режиме только для обнаружения).
#
SecRule REQBODY_ERROR "!@eq 0" \
"phase:2,t:none,log,deny,status:400,msg:'Не удалось разобрать тело запроса.',logdata:'%{reqbody_error_msg}',severity:2"
# По умолчанию будьте строги в том, что мы принимаем в многочастном/form-data
# теле запроса. Если правило ниже оказывается слишком строгим для вашей
# среды, вы можете рассмотреть возможность переключения его на режим только для обнаружения. Вам рекомендуется
# _не_ удалять его полностью.
#
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
"phase:2,t:none,log,deny,status:44,msg:'Многочастное тело запроса \
не прошло строгую проверку: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_SEMICOLON_MISSING}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IQ %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
IH %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
# Мы увидели что-то, что может быть границей?
#
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"phase:2,t:none,log,deny,status:44,msg:'Парсер многочастного тела обнаружил возможную несоответствующую границу.'"
# Настройка PCRE
# Мы хотим избежать потенциального состояния DoS с RegEx
#
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
# Некоторые внутренние ошибки устанавливают флаги в TX, и нам нужно будет их искать.
# Все они начинаются с "MSC_". В настоящее время существуют следующие флаги:
#
# MSC_PCRE_LIMITS_EXCEEDED: Превышены лимиты совпадения PCRE.
#
SecRule TX:/^MSC_/ "!@streq 0" \
"phase:2,t:none,deny,msg:'Флаг внутренней ошибки ModSecurity установлен: %{MATCHED_VAR_NAME}'"
# -- Обработка тела ответа --------------------------------------------------
# Позволяет ModSecurity доступ к телам ответов.
# Вам следует включить эту директиву, чтобы идентифицировать ошибки
# и проблемы утечки данных.
#
# Помните, что включение этой директивы повышает как
# потребление памяти, так и задержку ответа.
#
SecResponseBodyAccess On
# Какие MIME-типы ответов вы хотите инспектировать? Вам следует отрегулировать
# конфигурацию ниже, чтобы поймать документы, но избежать статических файлов
# (например, изображений и архивов).
#
SecResponseBodyMimeType text/plain text/html text/xml
# Буферизовать тела ответов длиной до 512 КБ.
SecResponseBodyLimit 524288
# Что происходит, когда мы сталкиваемся с телом ответа размером больше установленного
# лимита? По умолчанию мы обрабатываем то, что у нас есть, и пропускаем остальное.
# Это несколько менее безопасно, но не ломает никаких легитимных страниц.
#
SecResponseBodyLimitAction ProcessPartial
# -- Конфигурация файловой системы -------------------------------------------
# Место, где ModSecurity хранит временные файлы (например, когда
# ему нужно обработать загрузку файла, которая превышает установленный лимит).
#
# Эта настройка по умолчанию выбрана, потому что на всех системах есть доступ к /tmp, однако,
# это менее чем идеальный вариант. Рекомендуется указать место, которое будет приватным.
#
SecTmpDir /tmp/
# Место, где ModSecurity будет хранить свои постоянные данные. Эта настройка по умолчанию
# выбрана, потому что на всех системах есть доступ к /tmp, однако она
# также должна быть обновлена до места, к которому другие пользователи не могут получить доступ.
#
SecDataDir /tmp/
# -- Конфигурация обработки загрузок файлов --------------------------------
# Место, где ModSecurity хранит перехваченные загруженные файлы. Это
# место должно быть приватным для ModSecurity. Вы же не хотите, чтобы другие пользователи на
# сервере получали доступ к файлам, верно?
#
#SecUploadDir /opt/modsecurity/var/upload/
# По умолчанию сохраняются только файлы, которые были признаны необычными
# каким-либо образом (с помощью внешнего скрипта проверки). Для этого вам
# также потребуется хотя бы одно правило проверки файлов.
#
#SecUploadKeepFiles RelevantOnly
# Загруженные файлы по умолчанию создаются с правами, которые не позволяют
# ни одному другому пользователю получить доступ к ним. Возможно, вам потребуется ослабить это,
# если вы хотите интерфейс ModSecurity с внешней программой (например, антивирусом).
#
#SecUploadFileMode 0600
# -- Конфигурация журнала отладки -------------------------------------------
# Конфигурация журнала отладки по умолчанию дублирует сообщения об ошибках, предупреждениях
# и уведомлениях из журнала ошибок.
#
#SecDebugLog /opt/modsecurity/var/log/debug.log
#SecDebugLogLevel 3
# -- Конфигурация аудиторского журнала --------------------------------------
# Логи транзакций, отмеченных правилом, а также тех, которые
# приводят к ошибке сервера (определяемой кодами ответов 5xx или 4xx, исключая 404).
#
# Для логирования используйте RelevantOnly
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
# Логируйте все, что мы знаем о транзакции.
SecAuditLogParts ABIJDEFHZ
# Используйте один файл для логирования. Это намного удобнее для просмотра, но
# предполагает, что вы будете использовать аудиторский журнал только изредка.
#
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log
# Укажите путь для параллельного аудиторского логирования.
#SecAuditLogStorageDir /opt/modsecurity/var/audit/
# -- Разное ---------------------------------------------------------------
# Используйте наиболее часто применяемый разделитель параметров application/x-www-form-urlencoded.
# Вероятно, только одно приложение использует что-то другое, так что не ожидайте, что измените это значение.
#
SecArgumentSeparator &
# Разберитесь с версиями 0 (ноль) для куки, так как именно это использует большинство приложений.
# Использование неправильной версии куки может открыть вашу установку для
# атак уклонения (против правил, которые проверяют именованные куки).
#
SecCookieFormat 0
Примеры правил, которые имеют отношение к моему тесту на отправку POST с AES_ENCRYPT в полезной нагрузке, из /etc/modsecurity/whmcs_rules.conf:
SecRule REQUEST_URI|ARGS|REQUEST_BODY "aes_encrypt" "id:00101,phase:4,t:urlDecodeUni,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,log,deny,msg:'WHMCS'"
SecRule REQUEST_URI|ARGS|REQUEST_BODY "aes_encrypt" "id:00102,phase:4,t:urlDecodeUni,t:htmlEntityDecode,t:hexDecode,t:replaceComments,t:compressWhiteSpace,t:lowercase,log,deny,msg:'WHMCS'"
/var/log/modsec_audit.log (кусочек)
--bc497c3a-A--
[30/Oct/2013:12:33:19 +0000] UnD8jtXm0XMAABtcO10AAABA <client> 65312 <server> 443
--bc497c3a-B--
**залогировано, но удалено для конфиденциальности**
--bc497c3a-C--
**залогировано, но удалено для конфиденциальности**
--bc497c3a-F--
HTTP/1.1 403 Forbidden
X-Powered-By: PHP/5.3.3-7+squeeze17, PHP/5.3.3-7+squeeze17
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
--bc497c3a-E--
**ответ, который сгенерирован PHP-скриптом, когда отправляется POST**
--bc497c3a-H--
Сообщение: Доступ запрещен с кодом 403 (фаза 4). Сравнение шаблона "aes_encrypt" в ARGS:firstname. [файл "/etc/modsecurity/whmcs_rules.conf"] [строка "41"] [id "00101"] [msg "WHMCS"]
Действие: Перехвачено (фаза 4)
Таймер: 1383136398855159 530401 (- - -)
Таймер2: 1383136398855159 530401; combined=1155, p1=16, p2=14, p3=3, p4=1115, p5=6, sr=0, sw=1, l=0, gc=0
Тело ответа преобразовано: Декодировано
Производитель: ModSecurity для Apache/2.6.6 (http://www.modsecurity.org/).
Сервер: Apache/2.2.16 (Debian) mod_ssl/2.2.16 OpenSSL/0.9.8o
--bc497c3a-Z--
/etc/modsecurity/whmcs_rules.conf
Показывает, что это фаза:4, это часть response_body, вам, вероятно, нужно phase:1 (или, возможно, 2), который относится к request_headers (и request_body).
Таким образом, modsecurity сработает раньше.
Ах да, ModSecurity. Это всё, что я скажу! Кроме того, вопрос: у вас включена опция SecRuleInheritance
где-то дополнительно к SecRuleEngine
?
SecRuleInheritance On
SecRuleEngine On
А как насчет SecFilterScanPOST
?
SecFilterScanPOST On
Также, какая у вас конфигурация сервера? Эта инстанция ModSecurity работает на настройке Apache с единственным хостом или у вас установлено NameVirtualHost
?
И основываясь на проблемах, которые у меня были несколько лет назад, у вас установлено и активно mod_unique_id
? Некоторые конфигурации не имеют его, несмотря на возможность установки ModSecurity, и без него это может казаться активным, но не будет работать.
Также на сайте ModSecurity есть некоторые базовые примеры которые касаются настроек POST.
Я рекомендую установить правила Fail2Ban, которые будут помещать такие IP в бан на год.
Это делается путем добавления как фильтра, так и тюремного заключения в конфигурационные директории Fail2ban на сервере.
Убедитесь, что ВЫ ВКЛЮЧИЛИ правила ModSecurity вручную, отключив ручной ModSecurity для ваших фиксированных IP-адресов, чтобы вы не оказались заблокированными вне своего сервера, а также имели снимок на AWS (или другом) для восстановления вашего сервера, если заблокированы снаружи.
# Белый список xxxxx
SecRule REMOTE_ADDR "@ipMatch 127.0.0.1,xx.xx.xxx.xxx/24,yyy.yyy.yyy.yy" "id:9999993xxxx,phase:1,nolog,allow,ctl:ruleEngine=Off"
Также посмотрите, откуда это пришло, и, возможно, добавьте правило ModSecurity, которое заблокирует все IP адреса ASN, откуда это пришло.
Например:
# Заблокировать XXXXX Solutions, Inc. xxxxxxx.com - Риск мошенничества xx-xx-2024
SecRule REMOTE_ADDR "@ipMatch xxx.93.4.0/22,xxx.85.208.0/20,xxx.94.224.0/21,xxx.86.196.0/22,xxx.56.64.0/19" "id:99999932xxx,phase:1,log,drop,status:403,msg:'Заблокировать XXXXX Solutions, Inc. xxxxxxx.com - Риск мошенничества xx-xx-2024',logdata:'{REMOTE_ADDR=%{REMOTE_ADDR},REQUEST_URI=%{REQUEST_URI},QUERY_STRING=%{QUERY_STRING},REQUEST_METHOD=%{REQUEST_METHOD}}'"
Отличный веб-инструмент для проверки IP ASN:
А инструмент для получения списка всех диапазонов IP CIDR:
Обратите внимание, что после загрузки диапазонов IP в виде списка, упорядочите их и объедините диапазоны, если это возможно, т.е. установите cc.cc.0.0/16 вместо множества перечисленных диапазонов yy.yy.0.0/24.
Ответ или решение
Ответ на вопрос о ModSecurity, который не блокирует запросы, несмотря на триггер правила и возврат 403
Проблема, с которой вы столкнулись, действительно распространенная при использовании ModSecurity с Apache. Давайте рассмотрим несколько аспектов настройки, которые могут привести к указанному поведению.
1. Фазы обработки правил
Вы упомянули, что ваши правила триггерятся на фазе 4. Однако это означает, что проверка выполняется уже после обработки запроса, что позволяет PHP-скрипту обработать данные до того, как ModSecurity вернёт ответ. Чтобы предотвратить это поведение и остановить выполнение скрипта до обработки, рекомендуется, чтобы правила связывались с фазами 1 или 2.
SecRule REQUEST_URI|ARGS|REQUEST_BODY "aes_encrypt" "id:00101,phase:2,t:urlDecodeUni,t:htmlEntityDecode,log,deny,status:403,msg:'WHMCS'"
Здесь мы изменили фазу на 2, что позволит выполнять проверку до обработки тела запроса.
2. Проверка настроек конфигурации
Убедитесь, что в конфигурации ModSecurity включены следующие параметры:
SecRuleInheritance On
SecFilterScanPOST On
Эти команды обеспечивают, что обработка правил будет корректной для POST запросов.
3. Совместимость с Apache и модулями
Убедитесь, что у вас установлен и активирован модуль mod_unique_id
, который помогает ModSecurity работать в многопоточном окружении. Проверьте его наличие, выполнив следующую команду в терминале:
apache2ctl -M | grep unique_id
Если его нет в списке загруженных модулей, добавьте его в конфигурацию Apache.
4. Логи и отладка
Обратите внимание на логи ModSecurity. Убедитесь, что они правильно записываются и у вас есть возможность отслеживать инциденты. Установите уровень отладки для более детального анализа:
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 3
После того как вы установите уровень отладки, перезапустите Apache и проверьте логи на наличие сообщений об ошибках или другой информации, которая может помочь понять, почему запросы не блокируются.
5. Общие улучшения безопасности
Кроме настройки ModSecurity, рекомендуется использовать Fail2Ban для автоматической блокировки IP-адресов, которые создают подозрительную активность. Вы можете настроить фильтр, чтобы блокировать IP-адреса после определённого количества неудачных запросов.
6. IP и ASN блокировки
Анализируйте логи и определяйте, откуда поступают злонамеренные запросы. Установите правила для блокировки IP-адресов из определённых диапазонов или ASN:
SecRule REMOTE_ADDR "@ipMatch {список_IP}" "id:99999932xxx,phase:1,log,drop,status:403,msg:'Block определённых IP диапазонов'"
Заключение
Применяя предложенные изменения и дополнения, вы значительно повысите безопасность вашего приложения и минимизируете вероятность того, что злоумышленники смогут обойти вашу защиту. Настройка правильных фаз для правил и использование логирования — ключевые факторы в успешной интеграции ModSecurity. Убедитесь, что после вноса изменений вы перезапустили сервер Apache для применения новых настроек.