Nginx и ModSecurity

Date July 19th, 2013 Author Vitaly Agapov

Всем хорош Nginx, но у Apache всегда была целая россыпь козырей в рукаве, не позволявшая Nginx'у приблизиться к нему в его неимоверной крутости. Одним из таких козырей был плагин ModSecurity, про который я относительно недавно опять писал статейку. Каково же было моё удивление, тщательно перемешанное с радостью, когда я узнал, что ModSecurity теперь работает и с Nginx'ом и что этот плагин только-только вышел из беты. Радость была обоснована ещё и тем, что незадолго до того я искал какие-нибудь аналоги для использования. Тыкал палочкой Naxsi, но ничего под свои нужды так и не нашёл. А тут такой подарок.

Подарок оказался не без сюрпризов. Но обо всём по порядку.

Введение

Грубо говоря, запилили не столько модуль для Nginx, сколько standalone-реализацию самого ModSecurity, которую можно использовать практически с любым софтом, сделав небольшую прокладку-модуль. И как раз такую вот прокладку сделали для Nginx и для IIS. 

Компиляция и установка

На момент написания сего текста самыми свежими версиями являются nginx-1.4.2 и modsecurity-2.7.4. Само собой надо проверить, не появилось ли что-нибудь поновее.

Для подготовки процесса надо поставить некоторые пакеты, которые нам понадобятся:

apt-get install apache2-prefork-dev libxml2-dev libcurl4-openssl-dev

Для начала качаем и компилируем ModSecurity:

wget https://www.modsecurity.org/tarball/2.7.4/modsecurity-apache_2.7.4.tar.gz
tar -xzvf modsecurity-apache_2.7.4.tar.gz
cd modsecurity-apache_2.7.4
./configure --enable-standalone-module
make && make install

Теперь качаем и компилируем Nginx:

wget http://nginx.org/download/nginx-1.4.2.tar.gz
tar -xzvf nginx-1.4.2.tar.gz
cd nginx-1.4.2/
./configure --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/sbin/nginx --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-http_geoip_module --with-http_stub_status_module --with-http_ssl_module --with-ipv6 --with-http_perl_module --add-module=../modsecurity-apache_2.7.4/nginx/modsecurity/
make && make install

Само собой, в ./configure надо вставлять нужные для каждого конкретного случая параметры, но главным в нашем повествовании является ключ –add-module=../modsecurity-apache_2.7.4/nginx/modsecurity/, указывающий на то место, где лежит ModSecurity для Nginx.

При старте Nginx должен будет в error.log выплёвывать несколько строк, которые укажут нам, что ModSecurity работает и на коне:

2013/07/19 10:23:28 [notice] 24221#0: ModSecurity for nginx (STABLE)/2.7.4 (http://www.modsecurity.org/) configured.
2013/07/19 10:23:28 [notice] 24221#0: ModSecurity: APR compiled version="1.4.6"; loaded version="1.4.6"
2013/07/19 10:23:28 [notice] 24221#0: ModSecurity: PCRE compiled version="8.12 "; loaded version="8.12 2011-01-15"
2013/07/19 10:23:28 [notice] 24221#0: ModSecurity: LIBXML compiled version="2.7.8"

Настройка

Допустим мы хотим использовать уже готовый конфиг для ModSecurity, который у нас отлично работает на Apache. Что ж, это вполне возможно. Пусть в /etc/modsecurity/login.conf лужит набор директив, которые я разбирал в вышеупомянутой статье. Прежде всего надо добавить в каждый SecRule в список действий идентификатор правила вида id:<уникальное число>, так как он стал обязателен в новой версии ModSecurity. Например:

SecRule REQUEST_BASENAME "login.htm" "id:100,phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.requests=+1,expirevar:ip.requests=2"

Затем для их подключения надо в общем конфиге виртуал хоста или в нужном нам location'е добавить две строки:

ModSecurityEnabled on;
ModSecurityConfig /etc/modsecurity/login.conf;

Например:

location @backend{
    ModSecurityEnabled on;
    ModSecurityConfig /etc/modsecurity/login.conf;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
    proxy_redirect off;
 }

Кажись, на этом всё. Nginx можно рестартовать и наслаждаться жизнью. Но…

Segfault при попытке сделать reload

Да, при наличии в конфигурации ModSecurity директив SecRule процесс Nginx сегфолтится при попытке сделать релоад. При этом рестарт проходит отлично. Проблема касается только версии 2.7.4. Если в вашем будущем версия 2.7.5 уже зарелизилась, то проблема скорее всего уже отсутствует.

При релоаде в dmesg сваливаются ошибки вида:

nginx[25847]: segfault at 70 ip 00007ffe25a7eddc sp 00007fff895c8c00 error 4 in libapr-1.so.0.4.6[7ffe25a60000+38000]

При этом страницы не отдаются, а в логе Nginx'а валится:

[client 10.0.0.1] ModSecurity: Rule processing failed. [uri "/home.htm"]

С проблемой можно либо смириться и делать всегда рестарт, либо решить её следующим образом. Дело в том, что фикс этой проблемы уже есть в транке на GitHub'е. Вот соответствующий коммит: https://github.com/chaizhenhua/ModSecurity/commit/4ffdf9bf6d343e9146de360183629e0e0bc59add

Мы просто качаем файл https://raw.github.com/chaizhenhua/ModSecurity/4ffdf9bf6d343e9146de360183629e0e0bc59add/nginx/modsecurity/ngx_http_modsecurity.c и заменяем им тот, который лежит в modsecurity-apache_2.7.4/nginx/modsecurity/. После чего проворачиваем всю компиляцию заново. У меня сработало.

Tags: ,
Category: Nginx | No comments »

Comments

Leave a comment

 Comment Form