LibmodSecurity es un WAF(Web Application Firewall), este nos permite detectar ciertos tipos de ataques en base a unas reglas predefinidas, mediante estas firmas podremos detectar inyecciones SQL, XSS, LFI, RFI, también podemos disponer de reglas específicas para cierto software como Wordpress, cPanel, osComerce, Joomla, además podemos cargar reglas del proyecto OWASP o incluso las nuestras propias.
Hasta la version 2.X el proyecto se llamaba modsecurity, este dependia mucho de Apache y las adaptaciones a otros servidores eran meros wrappers entorno al modo de funcionamiento nativo de Apache, esto suponía una penalización en el rendimiento en los servidores que no son Apache. Podemos encontrar un análisis mas detallado en este enlace.
A partir de la version 3 ya no se trata de un módulo si no de una librería, cada servidor web accede a esta mediante un conector en forma de módulo. Nosotros vamos a utilizar los conectores para Apache y Nginx:
https://github.com/SpiderLabs/ModSecurity
https://github.com/SpiderLabs/ModSecurity-nginx
https://github.com/SpiderLabs/ModSecurity-apache
La versión 2.X todavía es mantenida, pero no es recomendable utilizarla:
https://github.com/SpiderLabs/ModSecurity/tree/v2/master
NOTA: Si utilizamos Nginx como balanceador se puede instalar en este punto común y protegería al resto de servidores web.
Este manual se compone de varias partes:
- Compilación e instalación de PHP
- Compilación e instalación de Apache + PHP
- Compilación e instalación de Nginx + PHP
- Código de prueba
- Compilación e instalación de MySQL
- Tests PHP e inyección
- Compilación e instalación de libmodsecurity
- Conector Apache
- Conector Nginx
- Configuración libmodsecurity
- Configuración Apache + libmodsecurity
- Configuración Nginx + libmodsecurity
- Test inyección2
- Concurrencia
- Custom config por tener dos servidores web simultáneos
- Integración con Telegram
- DEBUG
- Performance
Compilación e instalación de PHP
Empezamos compilando e instalando PHP, primero definiremos la versión de PHP:
PHP_TARGETS="php7-3"
PHP_INI_VERSION="production"
Definimos las use flags que deseamos en PHP:
dev-lang/php apache2 berkdb bzip2 cli crypt ctype curl curlwrappers exif fileinfo filter ftp gd gdbm hash iconv imap intl json mysql mysqli nls odbc pdo phar posix readline session simplexml soap sockets sqlite3 ssl sysvipc threads tokenizer unicode xml xmlreader xmlrpc xmlwriter zip zlib threads fpm cgi truetype bcmath
Añadimos la use flag fpm al eselect-php:
Compilamos PHP:
Configuramos el pool del php-fpm:
[www]
user = nobody
group = nobody
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
Arrancamos el PHP-FPM y lo añadimos al arranque:
rc-update add php-fpm default
Seleccionamos la versión de PHP que deseemos utilizar:
[1] php7.2 *
[2] php7.3
Reiniciamos el FPM:
Compilación e instalación de Apache + PHP
Ahora compilamos Apache con soporte para PHP-FPM:
APACHE2_MPMS="worker"
APACHE2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_core authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgi cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias proxy socache_shmcb proxy_fcgi authn_core unixd proxy_http proxy_http2"
www-servers/apache threads
Configuramos Apache para que cargue los módulos necesarios para ejecutar PHP a través de FPM:
APACHE2_OPTS="-D LANGUAGE -D PROXY -D CGI"
Creamos el vhost de apache, este quedará a la escucha en el puerto 8000:
Listen 8000
<VirtualHost *:8000>
ServerAdmin sys@alfaexploit.com
DocumentRoot /var/www/modsecurityTest/
ServerName modsecurityTest.alfaexploit.com
ErrorLog /var/log/apache2/modsecurityTest.error_log
CustomLog /var/log/apache2/modsecurityTest.access_log combined
DirectoryIndex index.php
AddHandler application/x-httpd-php .php .php5 .phtml
AddHandler application/x-httpd-php-source .phps
<FilesMatch ".php$">
SetHandler "proxy:fcgi://127.0.0.1:9000/"
</FilesMatch>
<Directory "/var/www/modsecurityTest/">
Options -Indexes +FollowSymLinks +ExecCGI
AllowOverride None
Require all granted
AllowOverride All
</Directory>
</VirtualHost>
Creamos los ficheros de log de nuestro proyecto web:
touch /var/log/apache2/modsecurityTest.access_log
Reiniciamos Apache:
Compilación e instalación de Nginx + PHP
Ahora compilamos Nginx:
Creamos el vhost de Nginx, este quedará a la escucha en el puerto 8001:
user nginx nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;
gzip off;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
index index.php;
server {
listen 0.0.0.0:8001;
server_name modsecurityTest.alfaexploit.com;
access_log /var/log/nginx/modsecurityTest.access_log main;
error_log /var/log/nginx/modsecurityTest.error_log info;
root /var/www/modsecurityTest/;
location ~* \.php$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
}
Reiniciamos Nginx:
Código de prueba
Para realizar las pruebas vamos a programar una pequeña aplicación web vulnerable a inyecciones SQL:
vi /var/www/modsecurityTest/index.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>
Compilación e instalación de MySQL
Compilamos MySQL:
emerge --config =dev-db/mysql-5.7.27-r1
/etc/init.d/mysql start
rc-update add mysql default
Creamos la base de datos a la que accede la aplicación web:
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;
Tests PHP e inyección
Comprobamos que la ejecución de PHP funciona correctamente:
Accedemos a las URLs correspondientes de Apache/Nginx:
http://modsecuritytest.alfaexploit.com:8000/info.php
http://modsecuritytest.alfaexploit.com:8001/info.php
Una vez comprobado, borramos el fichero de phpinfo:
Comprobamos que la app funciona correctamente en los dos servidores:
http://modsecurityTest.alfaexploit.com:PUERTO
Username: jesin
Password: pwd
Logged in
A Secret for you....
Comprobamos que la aplicación es vulnerable a inyecciones SQL, si introducimos como usuario:
Username: ' or true --
Logged in
A Secret for you....
Compilación e instalación de libmodsecurity
Compilamos libmodsecurity, esta no esta disponible en los repos de ninguna distro, hay que compilarla obligatoriamente desde las fuentes a no ser que se utilice
Nginx-Plus
, primero compilamos una dependencia de json:
Ahora la librería en sí misma:
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity/
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure --prefix=/ --with-yajl --enable-standalone-module
make -j4
make install
ln -s /include/modsecurity /usr/include/modsecurity
Conector Apache
Compilamos el conector para Apache:
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-apache.git
cd ModSecurity-apache
./autogen.sh
./configure
make -j4
make install
Comprobamos que el módulo existe:
-rwxr-xr-x 1 root root 29488 nov 4 13:01 /usr/lib64/apache2/modules/mod_security3.so
Cargamos el módulo:
LoadModule security3_module modules/mod_security3.so
Reiniciamos Apache y comprobamos que el módulo ha sido cargado:
/etc/init.d/apache2 modules
security3_module (shared)
Conector Nginx
Compilamos el conector para Nginx:
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
Recompilamos Nginx indicándole donde está el
módulo externo
:
NGINX_ADD_MODULES="/usr/src/ModSecurity-nginx"
Comprobamos que el módulo ha sido cargado:
http_v2_module
http_realip_module
http_ssl_module
stream_access_module
stream_geo_module
stream_limit_conn_module
stream_map_module
stream_return_module
stream_split_clients_module
stream_upstream_hash_module
stream_upstream_least_conn_module
stream_upstream_zone_module
mail_imap_module
mail_pop3_module
mail_smtp_module
module=/usr/src/ModSecurity
Configuración libmodsecurity
Configuramos modsec partiendo de una configuración base:
cd /etc/modsec
wget https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
mv modsecurity.conf-recommended modsecurity.conf
vi /etc/modsec/modsecurity.conf
SecRuleEngine On
SecAuditLogFormat json
SecAuditEngine RelevantOnly
SecAuditLog /var/log/modsec_audit.log
Hay un fichero necesario para el funcionamiento de libmodsecurity pero por alguna razón no se instala al hacer el make install, nos lo bajamos manualmente:
Nos bajamos las reglas OWASP:
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git
cd owasp-modsecurity-crs
cp crs-setup.conf.example crs-setup.conf
Le indicamos a modsec que cargue dichas reglas:
# Include the recommended configuration
Include /etc/modsec/modsecurity.conf
# OWASP CRS v3 rules
Include /usr/local/owasp-modsecurity-crs/crs-setup.conf
Include /usr/local/owasp-modsecurity-crs/rules/*.conf
Configuración Apache + libmodsecurity
Configuramos Apache para que utilice libmodsecurity:
Listen 8000
<VirtualHost *:8000>
ServerAdmin sys@alfaexploit.com
DocumentRoot /var/www/modsecurityTest/
ServerName modsecurityTest.alfaexploit.com
ErrorLog /var/log/apache2/modsecurityTest.error_log
CustomLog /var/log/apache2/modsecurityTest.access_log combined
DirectoryIndex index.php
modsecurity on
modsecurity_rules_file /etc/modsec/main.conf
AddHandler application/x-httpd-php .php .php5 .phtml
AddHandler application/x-httpd-php-source .phps
<FilesMatch ".php$">
SetHandler "proxy:fcgi://127.0.0.1:9000/"
</FilesMatch>
<Directory "/var/www/modsecurityTest/">
Options -Indexes +FollowSymLinks +ExecCGI
AllowOverride None
Require all granted
AllowOverride All
</Directory>
</VirtualHost>
NOTA: Si queremos hacerlo de forma global.
modsecurity on
modsecurity_rules_file /etc/modsec/main.conf
NOTA: Si se trata de un servidor en producción en preferible utilizar solo la detección antes, para poder ir adaptando las reglas a nuestro escenario particular.
SecRuleEngine DetectionOnly
Reiniciamos Apache:
Configuración Nginx + libmodsecurity
Configuramos Nginx para que utilice libmodsecurity:
user nginx nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;
gzip off;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
index index.php;
server {
listen 0.0.0.0:8001;
server_name modsecurityTest.alfaexploit.com;
modsecurity on;
modsecurity_rules_file /etc/modsec/main.conf;
access_log /var/log/nginx/modsecurityTest.access_log main;
error_log /var/log/nginx/modsecurityTest.error_log info;
root /var/www/modsecurityTest/;
location ~* \.php$ {
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
}
Reiniciamos Nginx:
Test inyección2
Si intentamos hacer login mediante la inyección SQL obtenemos:
Forbidden
You don't have permission to access this resource.
En los logs podemos ver las alertas:
Concurrencia
Si vamos a generar muchas entradas en el log es preferible escribir las entradas en formato concurrent, de este modo no se logearán en un fichero de texto de forma serializada, si no que se hará en distintos ficheros de forma paralela:
#SecAuditLogType Serial
SecAuditLogType Concurrent
SecAuditLog /var/log/modsec_audit.log
SecAuditLogStorageDir /opt/modsecurity/var/audit
Custom config por tener dos servidores web simultáneos
Como tenemos dos servidores web hay que darle acceso a los dos usuarios para que sean capaces de generar los ficheros de log:
gpasswd -a apache httpservers
gpasswd -a nginx httpservers
Creamos el directorio donde se almacenarán los logs:
chown -R root:httpservers /opt/modsecurity/var/audit/
chmod 775 /opt/modsecurity/var/audit/
Reiniciamos ambos servidores para aplicar la nueva configuración:
En cuanto hagamos saltar alguna regla podemos ver como se generar directorios nuevos:
total 12
drwxrwxr-x 3 root httpservers 4096 nov 4 13:37 .
drwxr-xr-x 4 root root 4096 nov 4 13:28 ..
drwxr-x--- 3 apache apache 4096 nov 4 13:37 20191104
NOTA: En este ejemplo Modsecurity es compartido por Apache y Nginx, cada servidor correr con su usuario correspondiente, por lo tanto cuando modsecurity genere logs lo hará con dicho usuario, en nuestro ejemplo esto genera problemas ya que el primero en generar el directorio del día podrá escribir en este denegando el acceso al segundo.
drwxr-x--- 3 apache apache 4096 nov 4 18:56 20191104
drwxr-x--- 3 nginx nginx 4096 nov 4 18:58 20191104
Para testear los dos servidores podemos eliminar los ficheros de log, hacer las pruebas con un servidor, volver a eliminar los logs y hacer las pruebas con el segundo servidor. Una alternativa sería tener dos configuraciones de /etc/modsec/modsecurity.conf cada una de ellas con un SecAuditLogStorageDir diferente.
Integración con Telegram
Una manera interesante de recibir las notificaciones es vía Telegram, para ello debemos crear un bot y añadirlo a un grupo donde enviaremos las alertas generadas por nuestro parser de logs.
Para almacenar el número de ataques por ip utilizaremos Redis.
Configuramos el servicio para que precise autenticación:
requirepass XXXXXXXXXXXXX
Arrancamos el servicio y lo metemos en el arranque:
rc-update add redis default
Si miramos los ficheros generados por libmodsecurity podemos ver como el campo message es nulo a excepción de la regla que ha macheado, en base a esto podemos desarrollar nuestro parser:
""
""
"SQL Injection Attack Detected via libinjection"
""
""
Preguntando por Internet comentan que a pesar de que las reglas tengan la opción nolog habilitada generan entradas de log con message nulo:
If you google the problem, you will see that it is a common bug
Instalamos las librerias de python necesarias:
pip install redis --user
pip install pyinotify --user
Programamos el parser para bloquear atacantes si en 60s se han realizado 5 o mas ataques:
#!/usr/bin/python
import pyinotify
import os
import json
import requests
import redis
import iptc
apikey = "XXXXX:YYYYYYYYYYYYYYYYYYYYYY"
telegramurl = "https://api.telegram.org/bot{}/sendMessage".format(apikey)
userid = "ZZZZZZZZZ"
try:
redisconnection = redis.Redis(host="127.0.0.1", port=6379, db=0, password='XXXXXXXXXXXXXX')
redisconnection.ping()
except:
print '++ ERROR: Cant connect to redis server'
quit()
class CommitFunction(pyinotify.ProcessEvent):
def process_default(self, event):
fullpath = event.path + '/' + event.name
if os.path.isfile(fullpath):
print '------------------------------------------------'
print "Processing: " + str(fullpath)
with open(fullpath) as fp:
for line in fp:
try:
rawdata = json.loads(line)
except:
continue
for messageline in rawdata['transaction']['messages']:
message = messageline['message']
data = messageline['details']['data']
# Delete not matched rules messages and anomaly score checks
if message != "" and data != "":
try:
timestamp = rawdata['transaction']['time_stamp']
except:
timestamp = 'NULL'
try:
attacker = rawdata['transaction']['request']['headers']['X-Forwarded-For']
except:
attacker = rawdata['transaction']['client_ip']
#attacker = 'NULL'
try:
useragent = rawdata['transaction']['request']['headers']['User-Agent']
except:
useragent = 'NULL'
try:
host = rawdata['transaction']['request']['headers']['Host']
except:
host = 'NULL'
try:
url = rawdata['transaction']['request']['uri']
except:
url = 'NULL'
try:
method = rawdata['transaction']['request']['method']
except:
method = 'NULL'
try:
payload = messageline['details']['data']
except:
payload = 'NULL'
print '>> Timestamp: ' + str(timestamp)
print 'Attacker: ' + str(attacker)
print 'UserAgent: ' + str(useragent)
print 'Message: ' + str(message)
print 'Host: ' + str(host)
print 'URL: ' + str(url)
print 'Method: ' + str(method)
print 'Payload: ' + str(payload)
print 'Checking redis IP: ' + str(attacker)
if redisconnection.get(attacker):
rediscounter = redisconnection.get(attacker)
#print 'rediscounter: ' + str(rediscounter)
if int(rediscounter) >= 5:
blacklistpath = '/etc/.blacklists/modsecurity.list'
if os.path.isfile(blacklistpath):
# Check if attacker is in blacklist
attackerfound = 0
print 'Checking if attacker is in blacklist'
with open(blacklistpath, "r") as blacklistcontent:
for blacklistline in blacklistcontent:
blacklistline = blacklistline.strip('\n')
print 'Comparing: ' + str(blacklistline) + ' against ' + str(attacker)
if blacklistline == attacker:
print 'Matched'
attackerfound = 1
break
# Add attacker to blacklist
if attackerfound == 0:
blacklistfile = open(blacklistpath,"a")
blacklistfile.write(attacker+'\n')
blacklistfile.close()
print 'Writting attacker ip to blacklist: ' + str(attacker)
else:
blacklistfile = open(blacklistpath,"w+")
blacklistfile.write(attacker+'\n')
blacklistfile.close()
# Check if attacker is in running iptables rules
print 'Checking in running iptables rules'
iptablesdata = iptc.easy.dump_table('filter', ipv6=False)
attackerfoundiptables = 0
for rule in iptablesdata['INPUT']:
if 'src' in rule and 'target' in rule:
if rule['src'] == attacker+'/32' and rule['target'] == 'DROP':
attackerfoundiptables = 1
print 'Matched'
break
# Add attacker to running iptables rules
if attackerfoundiptables == 0:
print 'Inserting in running iptables rules'
rule = iptc.Rule()
rule.src = attacker
rule.create_target("DROP")
rule.target = iptc.Target(rule, "DROP")
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
chain.insert_rule(rule)
msg = 'Banning time for: ' + str(attacker)
data = {"chat_id":userid, "text":msg}
try:
r = requests.post(telegramurl,json=data)
except:
print '++ Error sending telegram message'
continue
print 'Sending telegram alert'
msg = 'Date: ' + str(timestamp) + '\nAttacker: ' + str(attacker) + '\nUserAgent: ' + str(useragent) + '\nHost: ' + str(host) + '\nUrl: ' + str(url) + '\nAlert: ' + str(message) + '\nPayload: ' + str(payload)
data = {"chat_id":userid, "text":msg}
try:
r = requests.post(telegramurl,json=data)
except:
print '++ Error sending telegram message'
continue
else:
print 'Incrementing redis key value for IP: ' + str(attacker)
redisconnection.incr(attacker)
else:
print 'Creating redis key for IP: ' + str(attacker)
redisconnection.incr(attacker)
redisconnection.expire(attacker, 60)
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm)
wm.add_watch('/opt/modsecurity/var/audit/', pyinotify.IN_CREATE, rec=True, auto_add=True, proc_fun=CommitFunction())
notifier.loop(daemonize=False, callback=None)
Asignamos los permisos necesarios:
Podemos testear el parser mediante varias herramientas:
python sqlmap.py -u http://modsecuritytest.alfaexploit.com --data=“username=&password=”
perl nikto.pl -host http://modsecuritytest.alfaexploit.com:8001
ZAP
A continuación podemos ver las distintas notificaciones recibidas en Telegram:
Para que el parser autoarranque creamos el script:
/usr/bin/python /usr/local/modsecurityNotifier.py &
Lo arrancamos manualmente:
NOTA: Si compilamos iptables con la use flag static-libs el script en python fallará por alguna razón:
iptc.errors.XTablesError: can't find target DROP
Si en nuestra aplicación web hay alguna funcionalidad que requiera un comportamiento un poco fuera de lo normal podemos whitelistearla para que las reglas no salten cuando se trata de este sección:
vi /usr/local/owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
SecRule REQUEST_URI "@beginsWith /strangefunctionality" \
"id:1001,\
phase:1,\
pass,\
nolog,\
ctl:ruleEngine=Off"
Recargamos la configuración reiniciando los servidores web:
Si por otro lado queremos deshabilitar alguna regla en concreto utilizaremos la directiva SecRuleRemoveById
Nota : Esta directiva debe especificarse después de la regla a deshabilitar.
En mi caso estaba teniendo problemas con la regla:
CGI source code leakage
"ruleId": "950140",
"file": "/usr/local/owasp-modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf",
"lineNumber": "66",
Al mostrar código por la web la alarma es disparada por pensar que se está filtrando código fuente de la propia web:
# Include the recommended configuration
Include /usr/local/etc/modsec/modsecurity.conf
# OWASP CRS v3 rules
Include /usr/local/owasp-modsecurity-crs/crs-setup.conf
Include /usr/local/owasp-modsecurity-crs/rules/*.conf
# Disabled rules
Include /usr/local/etc/modsec/disabledRules.conf
SecRuleRemoveById 950140
DEBUG
Si queremos ver las peticiones de forma visual para incluir otros campos en las notificaciones podemos utilizar esta web:
http://jsonviewer.stack.hu/
También podemos aumentar el nivel de debug:
SecDebugLog /opt/modsecurity/var/log/debug.log
SecDebugLogLevel 9
touch /opt/modsecurity/var/log/debug.log
Reiniciamos los servidores web:
Consultamos los logs de debug:
Los posibles debug levels son:
- 0 No logging
- 1 Errors (e.g., fatal processing errors, blocked transactions)
- 2 Warnings (e.g., non-blocking rule matches)
- 3 Notices (e.g., non-fatal processing errors)
- 4 Informational
- 5 Detailed
- 9 Everything!
Para entornos en producción podemos generar solo logs pero no bloquear las peticiones hasta tener las reglas pulidas:
SecRuleEngine DetectionOnly
Otra opción es tan solo analizar un porcentaje de las peticiones: Adjust the percentage of requests that are funnelled into the Core Rules by setting TX.sampling_percentage below. The default is 100, meaning that every request gets checked by the CRS.
SecAction "id:900400,\
phase:1,\
pass,\
nolog,\
setvar:tx.sampling_percentage=10"
Performance
Por último dejo un enlace a un artículo sobre optimización de rendimiento:
https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/modsecurity-performance-recommendations/