Установка и настройка mod_security на Apache в Debian и Ubuntu

mod_security – это свободный фаервол веб-приложений (англ. Web Application Firewall, или WAF) для Apache, Nginx и IIS, который предоставляет гибкую систему правил для выполнения операций разного уровня сложности. Кроме того, mod_security поставляется с набором базовых правил фильтрации Core Rule Set (или CRS), среди которых есть правила для защиты от инъекций SQL, межсайтового скриптинга, троянов, ботов, захватов сеанса и многих других атак и взломов. В Apache mod_security является одним из дополнительных модулей, благодаря чему его легко установить и настроить.

Примечание: для выполнения данного руководства нужно предварительно установить программный стек LAMP.

Установка mod_security

ModSecurity можно скачать из стандартных репозиториев Debian/Ubuntu:

apt-get install libapache2-modsecurity

Убедитесь, что mod_security был загружен:

apachectl -M | grep --color security

Если на экране появился модуль по имени security2_module (shared), значит, все прошло успешно.

Установка ModSecurity включает в себя конфигурационный файл, который нужно переименовать:

mv /etc/modsecurity/modsecurity.conf{-recommended,}

Затем перезапустите Apache:

service apache2 reload

В каталоге логов Apache можно найти новый лог-файл для mod_security.

root@server:~# ls -l /var/log/apache2/modsec_audit.log
-rw-r----- 1 root root 0 Oct 19 08:08 /var/log/apache2/modsec_audit.log

Настройка mod_security

Для корректной работы установка mod_security «из коробки» нуждается в дополнительной настройке. Стандартный конфигурационный файл настроен на DetectionOnly, то есть, фаервол только отслеживает логи, при этом ничего не блокируя. Чтобы изменить это поведение, отредактируйте файл modsecurity.conf:

nano /etc/modsecurity/modsecurity.conf

Найдите в файле строку:

SecRuleEngine DetectionOnly

И измените ее так:

SecRuleEngine On

Примечание: при настройке mod_security на производственном сервере рекомендуется изменить эту директиву только после тестирования всех установленных правил.

Следующая директива, которую нужно отредактировать – это SecResponseBodyAccess. Она отвечает за буферизацию тела ответа; ее рекомендуется включать, только если требуется обнаружение и предохранение от утечки данных. Включенная директива (SecResponseBodyAccess On) не только будет использовать больше ресурсов сервера, но и увеличит размер лог-файла, следовательно, ее желательно отключить. Для этого найдите:

SecResponseBodyAccess On

И измените значение:

SecResponseBodyAccess Off

Теперь нужно ограничить максимальный объем данных, который можно передать веб-приложению. За это отвечают 2 директивы:

SecRequestBodyLimit
SecRequestBodyNoFilesLimit

Директива SecRequestBodyLimit задает максимальный размер данных POST. Если клиент отправляет больше данных, сервер выдаст ошибку 413 Request Entity Too Large. Если в веб-приложении нет механизма загрузки файлов, это значение можно существенно уменьшить. В конфигурационном файле задано следующее:

SecRequestBodyLimit 13107200

Что равно 12.5 мегабайтам.

Аналогично работает и директива SecRequestBodyNoFilesLimit. Разница только в том, что данная директива ограничивает размер данных POST за вычетом размера файлов.

Примечание: данное значение рекомендуется устанавливать по принципу ALARP (англ. «as low as reasonably practicable», то есть, исходя из оценки риска и задействованных ресурсов).

По умолчанию в конфигурационном файле задано:

SecRequestBodyNoFilesLimit 131072

Что равно 128KB.

В данном файле можно найти еще один параметр, влияющий на производительность сервера – это SecRequestBodyInMemoryLimit. Этот параметр задает размер данных тела ответа, который будет помещен в RAM; остальные данные отправятся на жесткий диск (как swap). Поскольку серверы, как правило, работают на SSD, это не проблема; однако, чтобы сэкономить RAM, значение можно уменьшить.

SecRequestBodyInMemoryLimit 131072

Это стандартное значение (128KB) в конфигурационном файле.

Проверка на инъекции SQL

Прежде чем определить политику фаервола при помощи правил, нужно создать PHP-скрипт, уязвимый к инъекциям SQL (SQL injection). Обратите внимание: это базовый логин скрипт PHP без обработки сессий. Не забудьте заменить пароль MySQL в нижеприведенном скрипте своим паролем.

/var/www/login.php
<html>
<body>
<?php
if(isset($_POST['login']))
{
$username = $_POST['username'];
$password = $_POST['password'];
$con = mysqli_connect('localhost','root','password','sample');
$result = mysqli_query($con, "SELECT * FROM `users` WHERE username='$username' AND password='$password'");
if(mysqli_num_rows($result) == 0)
echo 'Invalid username or password';
else
echo '<h1>Logged in</h1><p>A Secret for you....</p>';
}
else
{
?>
<form action="" method="post">
Username: <input type="text" name="username"/><br />
Password: <input type="password" name="password"/><br />
<input type="submit" name="login" value="Login"/>
</form>
<?php
}
?>
</body>
</html>

Такой скрипт будет отображать форму входа. После ввода правильных учетных данных на экране появится сообщение «A Secret for you».

Нужно внести учетные данные в БД; для этого создайте базу данных и таблицу MySQL:

mysql -u root -p

Это откроет командную строку mysql>.

create database sample;
connect sample;
create table users(username VARCHAR(100),password VARCHAR(100));
insert into users values('jesin','pwd');
insert into users values('alice','secret');
quit;

Откройте браузер и перейдите к http://yourwebsite.com/login.php, а затем введите правильные логин и пароль.

Username: User
Password: Pass

При этом появится сообщение о том, что вход выполнен успешно. Вернитесь и попробуйте указать заведомо неверные данные – на экране появится сообщение «Invalid username or password».

Как видите, скрипт работает должным образом. Теперь нужно выполнить тестовую инъекцию SQL, попробовав обойти ввод учетных данных. В поле Username введите:

' or true --

Примечание: после символов – необходимо поставить пробел, иначе инъекция не сработает.

Поле Password оставьте пустым и нажмите кнопку входа.

На экране появилось сообщение для авторизованных пользователей – значит, инъекция сработала.

Чтобы защитить сервер от подобных атак, нужно настроить правила брандмауэра.

Настройка правил mod_security

По умолчанию mod_security поставляется с базовым набором правил CRS (Core Rule Set), которые находятся в:

root@server:~# ls -l /usr/share/modsecurity-crs/
total 40
drwxr-xr-x 2 root root  4096 Oct 20 09:45 activated_rules
drwxr-xr-x 2 root root  4096 Oct 20 09:45 base_rules
drwxr-xr-x 2 root root  4096 Oct 20 09:45 experimental_rules
drwxr-xr-x 2 root root  4096 Oct 20 09:45 lua
-rw-r--r-- 1 root root 13544 Jul  2  2012 modsecurity_crs_10_setup.conf
drwxr-xr-x 2 root root  4096 Oct 20 09:45 optional_rules
drwxr-xr-x 3 root root  4096 Oct 20 09:45 util

Документацию можно найти в:

root@server:~# ls -l /usr/share/doc/modsecurity-crs/
total 40
-rw-r--r-- 1 root root   469 Jul  2  2012 changelog.Debian.gz
-rw-r--r-- 1 root root 12387 Jun 18  2012 changelog.gz
-rw-r--r-- 1 root root  1297 Jul  2  2012 copyright
drwxr-xr-x 3 root root  4096 Oct 20 09:45 examples
-rw-r--r-- 1 root root  1138 Mar 16  2012 README.Debian
-rw-r--r-- 1 root root  6495 Mar 16  2012 README.gz

Чтобы подгрузить эти готовые правила, нужно, чтобы веб-сервер Apache читал указанные выше каталоги. Для этого отредактируйте файл mod-security.conf:

nano /etc/apache2/mods-enabled/mod-security.conf

В <IfModule security2_module> </IfModule> внесите следующие параметры:

Include "/usr/share/modsecurity-crs/*.conf"
Include "/usr/share/modsecurity-crs/activated_rules/*.conf"

Директория activated_rules аналогична директории Apache mods-enabled. Правила доступны в каталогах:

/usr/share/modsecurity-crs/base_rules
/usr/share/modsecurity-crs/optional_rules
/usr/share/modsecurity-crs/experimental_rules

Чтобы активировать правила, нужно создавать символические ссылки в каталоге activated_rules. Создайте правило для защиты от SQL-инъекции.

cd /usr/share/modsecurity-crs/activated_rules/
ln -s /usr/share/modsecurity-crs/base_rules/modsecurity_crs_41_sql_injection_attacks.conf .

Чтобы новые правила вступили в исполнение, нужно перезапустить Apache.

service apache2 reload

Теперь вернитесь на созданную ранее страницу входа и попробуйте выполнить тестовую SQL-инъекцию. Если директива SecRuleEngine была включена, появится сообщение об ошибке 403 Forbidden. Если же значение DetectionOnly не было изменено, инъекция будет успешно выполнена, но сообщение о ней будет внесено в лог-файл modsec_audit.log.

Создание собственных правил mod_security

В данном разделе речь пойдет о создании цепочек правил.

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

/var/www/form.php
<html>
<body>
<?php
if(isset($_POST['data']))
echo $_POST['data'];
else
{
?>
<form method="post" action="">
Enter something here:<textarea name="data"></textarea>
<input type="submit"/>
</form>
<?php
}
?>
</body>
</html>

Пользовательские правила можно добавить в любой конфигурационный файл модуля  или разместить в каталогах mod_security. Создайте новый файл для правил.

nano /etc/modsecurity/modsecurity_custom_rules.conf

Добавьте в этот файл следующий код:

SecRule REQUEST_FILENAME "form.php" "id:'400001',chain,deny,log,msg:'Spam detected'"
SecRule REQUEST_METHOD "POST" chain
SecRule REQUEST_BODY "@rx (?i:(pills|insurance|rolex))"

Сохраните файл и перезапустите Apache.

Откройте http://yourwebsite.com/form.php в браузере и введите любое из этих слов: pills, insurance, rolex.

Появится либо страница ошибки 403 и запись лога, либо только запись лога (это зависит от настройки SecRuleEngine).

Синтаксис SecRule имеет такой вид:

SecRule VARIABLES OPERATOR [ACTIONS]

В данном случае используется действие (т.е., [ACTIONS]) chain для поиска совпадений в переменных REQUEST_FILENAME и form.php, REQUEST_METHOD и POST, REQUEST_BODY со строкой «@rx (?i:(pills|insurance|rolex))». Комбинация символов ?i: используется для регистронезависимого поиска. В случае  совпадения будут выполнены действия deny и log, а на экране появится сообщение «Spam detected». Действие chain означает «И», то есть, одновременное совпадение трех перечисленных правил.

Исключение хостов и каталогов из политики mod_security

Иногда бывает необходимо отключить действие брандмауэра для определенных каталогов или доменов (например, mod_security блокирует SQL-запросы к phpMyAdmin).

Примечание: рекомендуется исключить бэк-энды CMS-приложений.

Чтобы отключить mod_security для всего виртуального хоста, разместите в разделе <VirtualHost> следующее:

<IfModule security2_module>
SecRuleEngine Off
</IfModule>

Чтобы отключить mod_security для отдельного каталога:

<Directory "/var/www/wp-admin">
<IfModule security2_module>
SecRuleEngine Off
</IfModule>
</Directory>

Чтобы не отключать mod_security полностью, используйте параметр SecRuleRemoveById, чтобы исключить отдельное правило или цепочку правил, указав его ID.

<LocationMatch "/wp-admin/update.php">
<IfModule security2_module>
SecRuleRemoveById 981173
</IfModule>
</LocationMatch>

Чтобы получить более подробную информацию о работе mod_security, обратитесь к официальной документации фаервола.

Tags: , , , , , , , , ,

1 комментарий

Добавить комментарий