ModSecurity 3.x (nginx)

最後更新: 2022-12-16

介紹

ModSecurity 3.x is no longer just a module !!

新模式:

Nginx(Nginx-connector) -> Libmodsecurity

目錄

 


Complie libModSecurity

 

OS: Centos 7

# 準備 Libary

yum groupinstall 'Development Tools' -y

yum install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel zlib-devel

yum install ssdeep ssdeep-devel

yum install libxml2 libxml2-devel

yum install lmdb lmdb-devel

yum install lua lua-devel

yum install pcre2 pcre2-devel

# 準備 modsecurity

VER=3.0.8

mkdir /usr/src/modsecurity; cd /usr/src/modsecurity

# https://github.com/SpiderLabs/ModSecurity/releases

wget https://github.com/SpiderLabs/ModSecurity/releases/download/v${VER}/modsecurity-v${VER}.tar.gz

tar -zxf modsecurity-v${VER}.tar.gz

P.S.

libInjection 已經在 modsecurity source code 內, 不用再 Download

cd modsecurity-v${VER}

優化

./configure --prefix=/opt/modsecurity \
  --disable-doxygen-doc \
  --with-pcre2 --with-lmdb

make -j 2                        # 要有 2G ram 才 build 到

make install

du -sh /opt/modsecurity

214M    /opt/modsecurity

du -sh /opt/modsecurity/lib/*

166M    /opt/modsecurity/lib/libmodsecurity.a
47M     /opt/modsecurity/lib/libmodsecurity.so.3.0.8

 


Nginx Connector

 

它提供了

  • modsecurity on | off
  • modsecurity_rules_file <path to rules file>
  • modsecurity_rules_remote <key> <URL to rules>
  • modsecurity_rules <modsecurity rule>
  • modsecurity_transaction_id string

安裝方式

  • Dynamic Module
  • Static Link

Get connector source

cd /usr/src/modsecurity

# https://github.com/SpiderLabs/ModSecurity-nginx/releases

wget https://github.com/SpiderLabs/ModSecurity-nginx/releases/download/v1.0.3...

tar -zxf modsecurity-nginx-*.tar.gz

Get nginx source

nginx -v    # 查看當前 nginx 的 version

nginx version: nginx/1.22.1

NGINX=nginx-1.22.1

mkdir /usr/src/nginx; cd $_

wget http://nginx.org/download/${NGINX}.tar.gz

tar -zxf ${NGINX}.tar.gz

export MODSECURITY_INC="/opt/modsecurity/include/"

export MODSECURITY_LIB="/opt/modsecurity/lib/"

cd ${NGINX}

Configure source

nginx -V |& grep 'configure arguments' > build.sh

# 修改 build.sh 移除不使用的 Module

--with-http_dav_module
--with-http_random_index_module
--with-http_mp4_module
--with-http_flv_module
--with-http_slice_module
----
--with-mail
--with-mail_ssl_module
----
--with-stream
--with-stream_realip_module
--with-stream_ssl_module
--with-stream_ssl_preread_module
  • As a dynamic module
  • As a static module

As a dynamic module

./configure ... \
  --add-dynamic-module=/usr/src/modsecurity/modsecurity-nginx-v1.0.3 --with-compat

bash build.sh

make modules

ls -lh objs/ngx_http_modsecurity_module.so

-rwxr-xr-x 1 root root 379K Dec  6 11:39 objs/ngx_http_modsecurity_module.so

# 安裝 Module

cp $_ /etc/nginx/modules

nginx.conf

load_module modules/ngx_http_modsecurity_module.so;

As a static module

./configure ... \
  --add-module=/usr/src/modsecurity/modsecurity-nginx-v1.0.3

bash build.sh

make                # 別加 "-j" 否則會不夠 RAM

make install

建立 nginx 帳戶

useradd nginx -s /bin/nologin --home /var/spool/nginx -m

取代現有 nginx binary

mv /usr/sbin/nginx /usr/sbin/nginx.orig
cp objs/nginx /usr/sbin/
service nginx restart

ldd /usr/sbin/nginx | grep modsecurity

libmodsecurity.so.3 => /opt/modsecurity/lib/libmodsecurity.so.3 (0x00007fe701a6f000)

Remark

  • --with-compat                    # dynamic modules compatibility
  • --with-threads                    # enable thread pool support
  • --with-pcre-jit
  • --with-pcre=../pcre-8.44
  • --with-zlib=../zlib-1.2.11
  • --with-openssl=../openssl-1.1.1g
  • --with-openssl-opt=no-nextprotoneg

# PCRE version 8.44
wget https://ftp.pcre.org/pub/pcre/pcre-8.44.tar.gz && tar xzvf pcre-8.44.tar.gz

# zlib version 1.2.11
wget https://www.zlib.net/zlib-1.2.11.tar.gz && tar xzvf zlib-1.2.11.tar.gz

# OpenSSL version 1.1.1g
wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz && tar xzvf openssl-1.1.1g.tar.gz

unicode.mapping

mkdir /etc/nginx/modsec

cp /usr/src/modsecurity/modsecurity-v3.0.8/unicode.mapping $_

 


Nginx Service & Log

 

/etc/systemd/system/nginx.service

[Unit]
Description=nginx - high performance web server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

/etc/logrotate.d/nginx

/var/log/nginx/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 640 nginx adm
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

 


Nginx Settings

 

1) 原先設定好 Proxy

nginx.conf

http {
    ...
    server_names_hash_bucket_size  64;
    include conf.d/*.conf;
    include sites-enabled/*.conf;
}

/etc/nginx/proxy_params

proxy_set_header        Host                    $host;
proxy_set_header        X-Real-IP               $remote_addr;
proxy_set_header        X-Forwarded-For         $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto       $scheme;
add_header              X-Cache-Status          $upstream_cache_status;

sites-enabled/proxy_www.conf

# Backend setting
upstream MyBackend {
    ip_hash;
    server 192.168.123.11:80 max_conns=32;
    keepalive 10;
    keepalive_requests 3000;
    keepalive_timeout 100;
    zone myweb 128k;
}

# Frontend setting
server {
    listen       80;
    server_name  datahunter.org www.datahunter.org;
    root         /var/www/html;

    # Location Settings
    location ~ /\. { deny all; }
    location / {
        # ACL
        deny 123.123.123.123;
        # maintenance
        try_files /maintenance.html @proxy;
    }
    location @proxy {
        # Proxy Setting
        include             /etc/nginx/proxy_params;
        proxy_http_version  1.1;
        proxy_set_header    Connection "";
        proxy_pass          http://MyBackend;
    }
}

2) 加入 ModSecurity Setting

nginx.conf

load_module /opt/nginx/modules/ngx_http_modsecurity_module.so;

sites-available/proxy_www.conf

log_format extended '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" $request_id';
server {
    listen       80;
    server_name  waf.datahunter.org;

    # 不開 Folder 放 log, 可不用更新 logrotate 設定
    access_log   /var/log/nginx/waf.datahunter.org-access.log extended;
    error_log    /var/log/nginx/waf.datahunter.org-error.log;

    # Global 啟用 modsecurity
    modsecurity                 on;
    # 必須要 full path
    modsecurity_rules_file      /etc/nginx/modsec/modsecurity.rules;
    modsecurity_transaction_id  "$request_id";

    # 用來放 Error Page
    location = /40x.html {
        root /var/www/html;
        # 個別停用
        modsecurity off;
        internal;
    }
    location ~*
        \.(bmp|jpg|jpeg|png|svg|ico|gif|mp4|css|js|html|txt|woff2|zip|rar)$ {
        ...
    }
    location / {
        ...
    }
}

說明

modsecurity

# context: http, server, location

# Turns on ModSecurity functionality

modsecurity_rules_file

# context: http, server, location

# The location of the modsecurity configuration

Nginx only supports one 'ModSecurityConfig' directive

=> multiple 'Include' directive within your 'ModSecurityConfig'

modsecurity_transaction_id string

# context: http, server, location

# Allows to pass transaction ID from nginx instead of generating it in the library.

# you will be able to find correlations between access log and error log entries using the same unique identificator

modsecurity.rules

# bypass some rule
#SecRuleRemoveById 10

測試

systemctl restart nginx

/var/log/nginx/error.log

... [notice] 19874#19874: ModSecurity-nginx v1.0.2 (rules loaded inline/local/remote: 0/903/0)
... [notice] 19876#19876: ModSecurity-nginx v1.0.2 (rules loaded inline/local/remote: 0/903/0)

設定 TMP Folder

mkdir /var/lib/nginx/tmp/modsecurity /var/lib/nginx/modsecurity

chown nginx: /var/lib/nginx/tmp/modsecurity /var/lib/nginx/modsecurity

chmod 700 /var/lib/nginx/tmp/modsecurity /var/lib/nginx/modsecurity

modsecurity.rules

SecRuleEngine  On
SecTmpDir      "/var/lib/nginx/tmp/modsecurity/"
SecDataDir     "/var/lib/nginx/modsecurity/"

 


Debug

 

SecRuleEngine      On;
SecDebugLog        /var/log/nginx/modsec_debug.log;
SecDebugLogLevel   5;
  • 0: no logging
  • 1: errors (intercepted requests) only
  • 2: warnings
  • 3: notices
  • 4: details of how transactions are handled
  • 5: as above, but including information about each piece of information handled
  • 9: log everything, including very detailed debugging information

 


Clear Software Version

 

要安裝 nginx-more_clear_headers

sites-enabled/proxy_www.conf

server {
    ...
    # header setting
    more_clear_headers 'Server';
    more_clear_headers 'X-Powered-By';
}

 


加入 OWASP CRS Rules

 

Info: owasp_crs

Download

mkdir /usr/src/owasp-modsecurity-crs; cd $_

# https://github.com/coreruleset/coreruleset/releases

wget https://github.com/coreruleset/coreruleset/archive/v3.3.4.tar.gz

Install

tar -zxf v3.3.4.tar.gz

mv coreruleset-3.3.4 /usr/share

ln -s /usr/share/coreruleset-3.3.4 /usr/share/coreruleset

cp /usr/share/coreruleset/crs-setup.conf.example /usr/share/coreruleset/crs-setup.conf

location / {
    modsecurity_rules_file /etc/nginx/modsec/modsecurity.rules;
}

modsecurity.rules

#### CRS Setting
include /usr/share/coreruleset/crs-setup.conf
include /usr/share/coreruleset/rules/REQUEST-*.conf
#include /usr/share/coreruleset/rules/RESPONSE-*.conf

Test

http://localhost/?param="><script>alert(1);</script>

[1] waf.datahunter.org-access.log

... 403 ... ID

[2] grep ID waf.datahunter.org-error.log

... Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `15' )

 


Doc

 

  • https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v3.x)
  • https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)