Введение в mod_security


Использование веб-приложений в Интернет иногда похоже на игру в русскую рулетку. Несмотря на то, что достижение полной безопасности в Сети теоретически возможно, в реальной жизни, как всегда, все несколько сложнее. Необходима всего лишь единственная ошибка в коде, чтобы злоумышленник получил неограниченный доступ к Вашим данным. Если Вы используете веб-приложение со сложной функциональностью, то есть большая вероятность, что у него есть проблемы с обеспечением безопасности. Например, возьмем этот URL:
http://www.webapp.com/login.php?username=admin’;DROP%20TABLE%20users--

Если Ваше приложение уязвимо для SQL инъекций, то данный запрос может удалить всю информацию о пользователях в Вашем приложении. А Вы регулярно делаете “бэкапы” своей базы?
К счастью, модуль mod_security может защитить нас от множества веб-атак, включая SQL инъекции.

Почему мне следует использовать mod_security?

Полтора года назад, перед тем как я начал работать над mod_security, для контроля своего веб-трафика я использовал Short. Все прекрасно работало. Я задал в Short слова, которые меня интересовали, и он уведомлял меня всякий раз, когда одно из них появлялось во входящем потоке. Но я хотел большего. Я хотел свободы в определении сложных правил, а также возможности выполнения различных действий, определенных в HTTP. Использование же IDS отнимает очень много времени, а сама система является слишком дорогостоящей.

В то время я также пытался комбинировать использование mod_rewrite и mod_setenvif. Используя mod_rewrite, очень легко обнаружить слова drop и table, а затем перенаправить клиента с такого URL, тем самым предотвратив атаку. Это, конечно, убережет Вас от атак начинающих хакеров, но более опытный злоумышленник может просто использовать тот же URL, как и приведенный выше, но вместо метода GET использовать метод POST. Так как переменные метода POST обычно не обрабатываются в большинстве модулей, то данная атака успешно пройдет.
Убедившись в необходимости создания нового инструмента, я встал перед выбором: взять Java и создать полноценный реверс-прокси или создать модуль Apache, используя огромный объем существующего кода. Первый вариант требовал большего времени на работу, а результат, вероятно, был бы полезен только для очень ограниченного круга людей. Я же хотел создать что-то более гибкое и легкое в использовании, поэтому я выбрал второй вариант.
Возвращаясь к нашему примеру URL, для предотвращения SQL инъекции “drop table” с помощью mod_security, необходимо добавить в конфигурацию Apache следующее:
SecFilter “drop[[:space:]]table”
Единственным параметром директивы является регулярное выражение, на соответствие с которым будут проверяться все входящие запросы. Также этого можно достигнуть, используя mod_rewrite, но отличие в том, что mod_security обнаруживает и предотвращает атаки проводимые, как с использованием GET, так и с использованием POST.
Добавление возможности контроля метода POST запросов было большой проблемой для Apache 1.3.x, так как он не поддерживал фильтры.

Установка и конфигурирование

Наилучшим вариантом установки mod_security является компиляция его из исходных текстов. А если Вы используете Windows, и у Вас нет компилятора, то посетите сайт ModSecurity и скачайте оттуда уже скомпилированный модуль:
$/path/to/apache/bin/apxs -cia mod_security.c
# /path/to/apache/bin/apachectl stop
# /path/to/apache/bin/apachectl start
Перед тем как начать создавать правила, добавьте несколько строк в файл конфигурации httpd.conf:
<IfModule mod_security.c>
# Включает или выключает движок фильтра
SecFilterEngine On
# Проверка правильности кодирования URL
SecFilterCheckURLEncoding On
# Проверка UNICODE кодирования
SecFilterCheckUnicodeEncoding Off
# Использовать только байты из этого диапазона
SecFilterForceByteRange 0 255
# Вести лог только для подозрительных запросов
SecAuditEngine RelevantOnly
# Имя файла лога
SecAuditLog logs/audit_log
# Вывод отладочной информации (установлен минимальный уровень)
SecFilterDebugLog logs/modsec_debug_log SecFilterDebugLevel 0
# Осуществлять проверку POST запросов
SecFilterScanPOST On
# Для подозрительных запросов по умолчанию писать в лог
# и возвращать HTTP ответ с кодом 500

SecFilterDefaultAction “deny,log,status:500″
</IfModule>
Я оставил комментарии в тексте, поэтому назначение директив вполне очевидно. Данная конфигурация активирует mod_security, но больше ничего не делает. Желательно всегда начинать с простой конфигурации и добавлять в нее директивы по необходимости.

Так что он может делать?

Даже с такой простой конфигурацией mod_security делает два очень полезных дела. Во-первых, он выполняет несколько техник, предназначенных для предотвращения скрытых угроз, а во-вторых, он унифицирует весь входящий трафик. Это очень поможет, когда мы начнем добавлять правила фильтрации в конфигурацию сервера. Представьте, что Вы хотите запретить пользователям выполнять на сервере бинарный файл ps, используя регулярное выражение /bin/ps ax. Если не использовать mod_security, то это регулярное выражение будет отлавливать только идентичные обращения, а /bin//ps ax или /bin/ps%20ax, или /bin/./ps ax будет пропускать. А вот список того, что выполнит mod_security:
  • Удаляет множественные слеши (//).
  • Удаление директорий, ссылающихся на самих себя (./).
  • Обрабатывать и “\”, и “/” (только для Windows).
  • Производить декодирование URL.
  • Заменять пустые байты (%00) пробелами.
Также выполняется ряд проверок:
  • Проверка URL кодирования.
  • Проверка UNICODE кодирования.
  • Проверка частей запросов на определенные значения.

Действия

Всякий раз, когда срабатывает правило, выполняется некоторая последовательность действий. В большинстве случаев выполняются действия по умолчанию (они задаются директивой SecDefaultAction), но также возможно настроить действия на каждое правило с помощью второго аргумента в директиве SecFilter или третьего аргумента в SecFilterSelective. Вот список возможных действий:
  • deny - отвергает запрос.
  • allow - останавливает проверку правил и допускает запрос.
  • status:nnn - возвращает HTTP ответ с кодом nnn.
  • redirect:url - направляет запрос на абсолютный URL url.
  • exec: cmd - выполняет скрипт cmd.
  • log - запись запроса в лог ошибок.
  • nolog - не вносить запрос в лог.
  • pass - пропустить текущее правило и перейти к следующему
  • pause:nnn - приостановить обработку запроса на nnn миллисекунд. Будьте очень осторожны с этим действием. Apache остается занятым при остановке обработки. Вы фактически можете помочь злоумышленникам провести DoS-атаку.
Следующие действия влияют на порядок выполнения правил, подобно тому, как работает mod_rewrite:
  • chain - следующее правило в цепочке. Если правило в цепочке не срабатывает, то следующие за ним правила пропускаются.
  • skipnext:n - пропустить следующие n правил.

Правила фильтрации

Правила бывают двух видов. В простейшей форме:
SecFilter keyword
Проверяет наличие keyword (регулярное выражение) в первой строке входящего запроса (которая выглядит как GET /index.php HTTP/1.1) или в теле POST, если оно есть. Вместо него Вы можете использовать:
SecFilterSelective “произвольный список keyword, разделенный |”
Эта директива позволяет лучше контролировать то, что Вы собираетесь фильтровать (и тратит на выполнение меньше циклов процессора). Вместо продолжения дальнейшего разбора синтаксиса я приведу несколько интересных примеров. Пускай они дадут Вам стимул к действиям. Наиболее полезные правила всегда создаются при решении реально существующих проблем.
Данное правило пропустит все запросы от одного IP адреса (с моей рабочей станции). Другие правила обрабатываться не будут. Так как данные запросы не несут злого умысла, то они не попадают в лог:
SecFilterSelective REMOTE_ADDR “^IP_ADDRESS_HERE$” nolog,allow
Данное правило позволяет мне получить полный доступ с моего ноутбука, когда я в дороге. Так как я не знаю, какой IP адрес у меня будет, то доступ гарантируется всем клиентам, содержащим строку “Blend 42″ в поле User-Agent. Это слабая защита, но как метод идентификации - достаточно интересная.
SecFilterSelective HTTP_USER_AGENT “Blend 42″
Данное правило предотвращает SQL инъекции в cookie. Если существует cookie, запрос выполняется только в том случае, если cookie состоит только из цифр.
SecFilterSelective COOKIE_sessionid “!^(|[0-9]{1,9})$”
Данное правило требует наличия заголовков HTTP_USER_AGENT и HTTP_HOST в каждом запросе. Злоумышленники часто работают, используя простые средства (в т.ч. telnet), и не посылают всех заголовков, которые отсылает браузер. Такие запросы будут отвергнуты, помещены в лог и проконтролированы.
SecFilterSelective “HTTP_USER_AGENT|HTTP_HOST” “^$”
Данное правило запрещает закачку файлов на сервер. Это простая, но эффективная защита; отказ запросов основан на типе контента, используемого при закачке файлов.
SecFilterSelective “HTTP_CONTENT_TYPE” multipart/form-data
Это правило заносит в лог запросы без заголовка “Accept” для последующей его проверки. “Ручные” запросы часто не содержат всех HTTP заголовков. Заголовок “Keep-alive” следующий кандидат на такую проверку.
SecFilterSelective “HTTP_ACCEPT” “^$” log,pass
Это правило отсылает мне письмо всякий раз, когда начальник вновь забывает свой пароль :-) . Тут у нас две директивы. Первая срабатывает только тогда, когда запрошен определенный файл (в данном случае файл, отображающий сообщение о неверном пароле). Вторая директива проверяет имя пользователя на соответствие с “ceo”. И если имя совпадает, то вызывается внешний скрипт:
SecFilterSelective REQUEST_URI “login_failed\.php” chain
SecFilterSelective ARG_username “^ceo$” log,exec:/home/apache/bin/notagain.pl
Данное правило отправляет поискового робота Googlebot обратно на сайт Google. Используется заголовок User-Agent. Данный запрос не попадает в лог.
SecFilter HTTP_USER_AGENT “Google” nolog,redirect:http://www.google.com
Данное правило проверяет все переменные JavaScript, пропуская переменную с именем html. Другие же переменные JavaScript отвергаются, так как они могут вызвать ошибки в некоторых приложениях (актуально для CMS средств).
SecFilter “ARGS|!ARG_html” “<[:space:]*script”
И в завершение покажем пример, как использовать множественную настройку mod_security. Это означает, что можно создавать правила для определенного пути. Запомните директиву SecFilterInheritance. C ее помощью мы сообщаем mod_security, что необходимо игнорировать все правила вышестоящего контекста.
<Location /anotherapp/>
SecFilterForceByteRange 32 126
# Использование этой директивы НЕ игнорирует правила вышестоящего контекста
SecFilterInheritance Off
# Разработчики часто используют специальные переменные
# для работы в Debug режиме. Эти два правила
# разрешают использовать переменную "debug", но только для внутренней сети

SecFilterSelective REMOTE_ADDR “!^192.168.254.” chain
SecFilterSelective ARG_debug “!^$”
</Location>

Производительность

У меня никогда не было проблем с производительностью при использовании mod_security. Тем не менее, на практике производительность немного падает. На реальных веб-сайтах один запрос страницы может вызвать множество запросов на графику, таблицы стилей и JavaScript файлы. Mod_security не рассматривает дочерние запросы, только если это не задать явно следующей директивой:
SecFilter DynamicOnly
Операции ввода/вывода всегда были узким местом. Убедитесь, что на работающем сервере выключен режим отладки и используйте максимальный уровень ведения лога только тогда, когда он Вам действительно нужен. В представленной выше конфигурации лог ведется только для “подозрительных” запросов, т.е. для тех, которые приводят к срабатыванию фильтров.

Другие возможности

Внутренний chroot
Если Вам когда-нибудь приходилось использовать chroot для веб-сервера, то Вы, вероятно, знаете какая это непростая задача. Для mod_security эта сложность исчезает. Достаточно использовать одну директиву:
SecChrootPath /chroot/home/web/apache
Единственное требование - это, чтобы путь сервера был подобен обычному пути (например: /home/web/apache).

Подмена сигнатуры сервера

Злоумышленники и автоматические скрипты для сбора данных о сервере часто используют HTTP-заголовок “Server”, который отсылается с каждым запросом. Вы можете изменить его путем внесения изменения в код Apache, но также это можно сделать, используя следующую директиву. Вы можете воспользоваться этой возможностью только для Apache 1.x. Модуль mod_headers, включенный в Apache 2.x, перехватывает исходящие заголовки и меняет их “на лету”:
SecServerSignature “Microsoft-IIS/5.0″

Ссылки

Автор: Иван Ристик (Ivan Ristic)
Перевод: Сипягин Максим
Оригинал документа (en)

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • News2.ru
  • NewsLand.ru
  • del.icio.us
  • BobrDobr.ru
  • Ma.gnolia
  • Digg
  • Reddit
  • Technorati
  • Slashdot
  • Netscape
  • DZone
  • ThisNext
  • Furl
  • YahooMyWeb
Опубликовано в: Модули Apache Февраль 19, 2006

8 Комментариев »

  1. Спасибо за статью, очень классно написано. Мне понравилось.

    Комментарий от Данил — Май 30, 2006 @ 3:36 am

  2. вопрос немного не в тему, но спросить хотелось бы… можно ли директивы, а точнее условия из mod_security для Apache использовать в .htaccess для защиты от XSS-скриптинга и червей? Просто хостер не позволяет управление данным модулем через .htaccess…
    Например я использую в .htaccess:
    RewriteOptions inherit
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)wget%20(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)system(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)exec(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)tar%20(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)cd%20(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)http://(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)union%20(.*) [OR,NC]
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)%20/tmp(.*) [OR,NC]
    RewriteCond %{HTTP_COOKIE}% s(.*):%22test1%22%3b
    RewriteRule ^.*$ http://www.mysite.com/alert.php [NC,F]
    (список queries указан не полный) В итоге при наличии в строке подозрительных запросов выдается 403 и в лог пишутся данные о запросившем.
    А в mod_security (http://www.modsecurity.org/) есть к примеру такие фильтры:
    # WEB-ATTACKS chmod command attempt
    SecFilter “/bin/chmod”
    # WEB-ATTACKS chgrp command attempt
    SecFilter “/chgrp”
    # WEB-ATTACKS chown command attempt
    SecFilter “/chown”
    # WEB-ATTACKS chsh command attempt
    SecFilter “/usr/bin/chsh”
    # WEB-ATTACKS tftp command attempt
    SecFilter “tftp\x20″
    # WEB-ATTACKS gcc command attempt
    SecFilter “gcc\x20-o”
    # WEB-ATTACKS cc command attempt
    #SecFilter “cc\x20″
    # WEB-ATTACKS /usr/bin/cpp command attempt
    SecFilter “/usr/bin/cpp”
    # WEB-ATTACKS cpp command attempt
    SecFilter “cpp\x20″
    # WEB-ATTACKS /usr/bin/g++ command attempt
    SecFilter “/usr/bin/g\+\+”
    Вопрос: корректно ли будет перенести queries из фильтров mod_secure в просто mod_rewrite, напрмер:
    RewriteCond %{REQUEST_URI}?%{QUERY_STRING} ^(.*)/usr/bin/g\+\+(.*) [OR,NC]
    и будет ли это работать?

    Комментарий от termenvox — Июль 14, 2006 @ 10:12 am

  3. Пара замечаний по тексту, за который (особенно Location, сам как-то не сообразил):
    - если LoadModule mod_rewrite до LoadModule mod_security, то в Location упадёт уже переписанный URL (что логично, но может быть не совсем очевидно, если давно собственных конфигов не видать);
    - googlebot, помнится, и просто robots.txt слушается, в отличие от отморозков с msn. Правда, последние вроде тоже за ум взялись — начав рисовать именно для них (гугль-то мы любим ;) правило, не обнаружил в логе зацепок.
    Спасибо!
    --
    mike@,
    майнтейнер apache-1.3
    в ALT Linux

    Комментарий от Michael Shigorin — Октябрь 21, 2006 @ 3:58 pm

  4. Замечательная статейка, хотя побаловатся реврайтом можно сверх наголову. К примеру не фильтровать лишнее а только фильтровать нужное, для ресурсов у которых продумана логика легче сделать именно так. Т.е. на уровне rewrite проверять подходит ли входящий поток под условия если ок пропускать если нет - то это потанциальная атака. Т.е в ряде случаем легче описать правильные запросы, чем описать не правильные. Но это как говорится дело техники :)

    Комментарий от LIGHT — Май 17, 2007 @ 1:40 pm

  5. Замечательно все расписано, главное что по-русски :)

    Комментарий от Dimka — Май 25, 2007 @ 8:32 pm

  6. не Short, а Snort )

    Комментарий от Anonymous — Январь 31, 2008 @ 1:00 pm

  7. Полезная статья!

    Комментарий от pento — Июль 30, 2008 @ 2:32 pm

  8. А куда это нужно вставлять

    Комментарий от nemaster — Октябрь 7, 2008 @ 9:51 pm

Оставить комментарий

You must be logged in to post a comment.

Работает на WordPress