# nginx - 整合 modsecurity 做 waf
# 简介
ModSecurity 是一个开源的、跨平台的 Web 应用防火墙(WAF),被称为 WAF 界的 “瑞士军刀”。它可以通过检查 Web 服务接收到的数据,以及发送出去的数据来对网站进行安全防护。
主要提供一下规则:
- SQL Injection (SQLi):阻止 SQL 注入
- Cross Site Scripting (XSS):阻止跨站脚本攻击
- Local File Inclusion (LFI):阻止利用本地文件包含漏洞进行攻击
- Remote File Inclusione (RFI):阻止利用远程文件包含漏洞进行攻击
- Remote Code Execution (RCE):阻止利用远程命令执行漏洞进行攻击
- PHP Code Injectiod:阻止 PHP 代码注入
- HTTP Protocol Violations:阻止违反 HTTP 协议的恶意访问
- HTTPoxy:阻止利用远程代理感染漏洞进行攻击
- Sshllshock:阻止利用 Shellshock 漏洞进行攻击
- Session Fixation:阻止利用 Session 会话 ID 不变的漏洞进行攻击
- Scanner Detection:阻止黑客扫描网站
- Metadata/Error Leakages:阻止源代码 / 错误信息泄露
- Project Honey Pot Blacklist:蜜罐项目黑名单
- GeoIP Country Blocking:根据判断 IP 地址归属地来进行 IP 阻断
# 开始安装
# 安装后续所需要的依赖:
yum install -y gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel pcre-devel lmdb-devel libxml2-devel ssdeep-devel lua-devel libtool autoconf automake wget epel-release openssl-devel
# 下载必要的文件:
- 创建目录:
mkdir -p /home/software/nginx-mod | |
cd /home/software/nginx-mod |
下载 ModSecurity 安装包
wget http://www.modsecurity.cn/download/modsecurity/modsecurity-v3.0.4.tar.gz
下载 ModSecurity 和 nginx 的桥接文件
wget https://codeload.github.com/SpiderLabs/ModSecurity-nginx/zip/refs/heads/master (这个可能下载下来的有问题,可以在本机电脑下载后上传)下载 nginx 安装包
wget http://nginx.org/download/nginx-1.25.5.tar.gz
下载 ModSecurity 核心规则文件
wget http://www.modsecurity.cn/download/corerule/owasp-modsecurity-crs-3.3-dev.zip
最后结果:
-rw-r--r--. 1 root root 260374 5月 13 2020 modsecurity-nginx-master.zip | |
-rw-r--r--. 1 root root 2806291 5月 13 2020 modsecurity-v3.0.4.tar.gz | |
-rw-r--r--. 1 root root 1244060 4月 16 22:37 nginx-1.25.5.tar.gz | |
-rw-r--r--. 1 root root 460374 5月 13 2020 owasp-modsecurity-crs-3.3-dev.zip |
# 安装 ModSecurity:
#解压 | |
tar -zxvf modsecurity-v3.0.4.tar.gz | |
cd /home/software/nginx-mod/modsecurity-v3.0.4 | |
#编译 | |
sh build.sh | |
./configure | |
#安装,这一步会有点久,请耐心等待 | |
make && make install | |
libtool: link: g++ -g -O2 -o rules_optimization optimization/rules_optimization-optimization.o -L/usr/lib64/ ../src/.libs/libmodsecurity.a -lcurl -lGeoIP -lrt -lxml2 -lz -lm -ldl -llua-5.1 -lpcre -lyajl | |
make[2]: 离开目录“/home/software/nginx-mod/modsecurity-v3.0.4/test” | |
make[1]: 离开目录“/home/software/nginx-mod/modsecurity-v3.0.4/test” | |
make[1]: 进入目录“/home/software/nginx-mod/modsecurity-v3.0.4” | |
make[1]: 对“all-am”无需做任何事。 | |
make[1]: 离开目录“/home/software/nginx-mod/modsecurity-v3.0.4” | |
make: *** 没有规则可以创建目标“instal”。 停止。 | |
#最后看到有上面的内容表示安装完成 |
# 安装 ModSecurity-Nginx
#解压: | |
unzip modsecurity-nginx-master.zip | |
#移动到 modsecurity 目录下: | |
mv modsecurity-nginx-master /home/software/nginx-mod/modsecurity-v3.0.4/modsecurity-nginx | |
#现在的结构 | |
cd /home/software/nginx-mod/modsecurity-v3.0.4 | |
-rwxr-xr-x. 1 1000 1000 707870 5月 11 11:05 configure | |
-rw-r--r--. 1 root root 174749 5月 11 11:07 Makefile | |
-rw-r--r--. 1 1000 1000 10210 1月 13 2020 modsecurity.conf-recommended | |
drwxr-xr-x. 5 root root 201 5月 11 11:11 modsecurity-nginx | |
drwxr-xr-x. 14 1000 1000 4096 5月 11 11:14 src | |
... | |
#可以看到 modsecurity-nginx 文件夹在 modsecurity-v3.0.4 目录下 |
# 安装 nginx
注:如果已经安装了 nginx 可以在安装的时候指定安装路径避免和原本的 nginx 冲突覆盖。
可以使用以下命令查看安装 nginx 的路径(如果是下载的二进制文件编译安装的)
./nginx -V | |
nginx version: nginx/1.25.5 | |
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) | |
built with OpenSSL 1.0.2k-fips 26 Jan 2017 | |
TLS SNI support enabled | |
configure arguments: --prefix=/usr/local/nginx-1.25.5 | |
可以看到我的nginx版本是1.25.5,安装路径是/usr/local/nginx-1.25.5 |
开始安装:
#解压: | |
tar -zxvf nginx-1.25.5.tar.gz | |
#改个名字 | |
mv nginx-1.25.5 nginx-1.25.5-install | |
cd nginx-1.25.5-install | |
#编译 | |
./configure --prefix=/home/software/nginx-mod/nginx-1.25.5 --with-http_stub_status_module --with-http_ssl_module --with-file-aio --with-http_realip_module --add-dynamic-module=/home/software/nginx-mod/modsecurity-v3.0.4/modsecurity-nginx | |
#--add-dynamic-module 指定要添加的 module 这里添加的是 modsecurity 指定了路径 | |
#结果: | |
Configuration summary | |
+ using system PCRE library | |
+ using system OpenSSL library | |
+ using system zlib library | |
nginx path prefix: "/home/software/nginx-mod/nginx-1.25.5" | |
nginx binary file: "/home/software/nginx-mod/nginx-1.25.5/sbin/nginx" | |
nginx modules path: "/home/software/nginx-mod/nginx-1.25.5/modules" | |
nginx configuration prefix: "/home/software/nginx-mod/nginx-1.25.5/conf" | |
nginx configuration file: "/home/software/nginx-mod/nginx-1.25.5/conf/nginx.conf" | |
nginx pid file: "/home/software/nginx-mod/nginx-1.25.5/logs/nginx.pid" | |
nginx error log file: "/home/software/nginx-mod/nginx-1.25.5/logs/error.log" | |
nginx http access log file: "/home/software/nginx-mod/nginx-1.25.5/logs/access.log" | |
nginx http client request body temporary files: "client_body_temp" | |
nginx http proxy temporary files: "proxy_temp" | |
nginx http fastcgi temporary files: "fastcgi_temp" | |
nginx http uwsgi temporary files: "uwsgi_temp" | |
nginx http scgi temporary files: "scgi_temp" | |
#如果最后出现上面的字样表示编译成功 | |
#执行安装: | |
make && make install | |
#结果 | |
cp objs/ngx_http_modsecurity_module.so '/home/software/nginx-mod/nginx-1.25.5/modules/ngx_http_modsecurity_module.so' | |
make[1]: 离开目录“/home/software/nginx-mod/nginx-1.25.5-install” | |
#如果出现上面的字样表示安装成功 | |
#现在的结构 | |
drwxr-xr-x. 13 1000 1000 4096 5月 11 11:49 modsecurity-v3.0.4 | |
drwxr-xr-x. 12 root root 166 5月 11 14:36 nginx-1.25.5 | |
drwxr-xr-x. 9 502 games 186 5月 11 11:52 nginx-1.25.5-install | |
-rw-r--r--. 1 root root 460374 5月 13 2020 owasp-modsecurity-crs-3.3-dev.zip | |
#进入安装好的 nginx 下看看 | |
drwxr-xr-x. 3 root root 4096 5月 11 14:31 conf | |
drwxr-xr-x. 2 root root 40 5月 11 11:54 html | |
drwxr-xr-x. 2 root root 58 5月 11 14:50 logs | |
drwxr-xr-x. 2 root root 44 5月 11 11:54 modules | |
drwxr-xr-x. 2 root root 19 5月 11 11:54 sbin |
# 开始配置相关的防火墙规则
将 ModSecurity 下的配置文件 复制到 nginx.config 目录,方便后期更改配置:
mkdir -p /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity
#复制核心配置文件
cp /home/software/nginx-mod/modsecurity-v3.0.4/modsecurity.conf-recommended /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/modsecurity.conf
cp /home/software/nginx-mod/modsecurity-v3.0.4/unicode.mapping /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity
修改 nginx.conf 配置文件:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
#添加了这一行,加载 modsecurity 模块,让 nginx 支持 waf
load_module modules/ngx_http_modsecurity_module.so;
events {
worker_connections 1024;
}
http {
#开启 modsecurity
modsecurity on;
#指定 modsecurity 核心配置文件
modsecurity_rules_file /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/modsecurity.conf;
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
启动测试是否正常加载:
#检查配置文件
./nginx -t
#启动
./nginx
#没有报错正常启动
现在只是搭建好,还需要打开和添加防火墙规则:
#解压下载好的规则文件
unzip owasp-modsecurity-crs-3.3-dev.zip
cd owasp-modsecurity-crs-3.3-dev
#配置文件
cp crs-setup.conf.example /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/crs-setup.conf
#复制所有规则配置文件
cp -r rules /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/
cd /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules
mv REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
mv RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
关于上面的两个文件说明:
#1. 通过全局方式禁用规则,指令需加载在 RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf 文件中,也可创建自定义规则文件,但需先加载 ModSecurity 核心规则文件,再加载自定义规则文件。
#2. 通过白名单方式禁用规则,指令需加载在 REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf 文件中,也可创建自定义规则文件,但需先加载自定义规则文件,再加载 ModSecurity 核心规则文件。
将防火墙配置文件加载到 nginx 中
#打开配置:
vim /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/modsecurity.conf
注释:#SecRuleEngine DetectionOnly
添加:SecRuleEngine On
注释:#SecAuditLogParts ABIJDEFHZ
添加:SecAuditLogParts ABCDEFHZ
添加防护规则文件
Include /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/crs-setup.conf
Include /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules/*.conf
重启 nginx 测试:
./nginx -t
./nginx -s reload
测试会被拦截的请求看看是否被拦截
wget http://192.168.0.1/projectName?PHPRC=/dev/fd/0
可以看到被拦截了 返回403
# 查看拦截情况的日志:
#日志默认在 | |
/var/log/modsec_audit.log | |
#我们监听日志文件,请求一个会被拦截的请求试试 | |
tail -f /var/log/modsec_audit.log | |
#接着请求 | |
wget http://192.168.0.1/projectName?PHPRC=/dev/fd/0 | |
#日志打印内容 | |
---q2JtnKPF---A-- | |
[11/May/2024:20:27:09 +0800] 17154304293.336548 10.160.242.40 46266 192.168.0.1 443 | |
---q2JtnKPF---B-- | |
GET /projectName/?PHPRC=/dev/fd/0 HTTP/1.1 | |
Host: 192.168.0.1 | |
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:79.0) Gecko/20100101 Firefox/79.0 | |
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 | |
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 | |
Accept-Encoding: gzip, deflate, br | |
Connection: keep-alive | |
Upgrade-Insecure-Requests: 1 | |
---q2JtnKPF---F-- | |
HTTP/1.1 403 | |
Server: nginx | |
Date: Sat, 11 May 2024 12:27:09 GMT | |
Content-Length: 146 | |
Content-Type: text/html | |
Connection: keep-alive | |
Strict-Transport-Security: max-age=31536000; includeSubDomains | |
---q2JtnKPF---H-- | |
ModSecurity: Warning. Matched "Operator `Rx' with parameter `^[\d.:]+$' against variable `REQUEST_HEADERS:Host' (Value: `192.168.0.1' ) [file "/home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "722"] [id "920350"] [rev ""] [msg "Host header is a numeric IP address"] [data "192.168.0.1"] [severity "4"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "192.168.0.1"] [uri "/projectName/"] [unique_id "17154304293.336548"] [ref "o0,13v42,13"] | |
ModSecurity: Warning. Matched "Operator `PmFromFile' with parameter `unix-shell.data' against variable `ARGS:PHPRC' (Value: `/dev/fd/0' ) [file "/home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf"] [line "496"] [id "932160"] [rev ""] [msg "Remote Command Execution: Unix Shell Code Found"] [data "Matched Data: dev/fd/ found within ARGS:PHPRC: /dev/fd/0"] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-shell"] [tag "platform-unix"] [tag "attack-rce"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "OWASP_CRS/WEB_ATTACK/COMMAND_INJECTION"] [tag "WASCTC/WASC-31"] [tag "OWASP_TOP_10/A1"] [tag "PCI/6.5.2"] [hostname "192.168.0.1"] [uri "/projectName/"] [unique_id "17154304293.336548"] [ref "o1,7v17,9t:urlDecodeUni,t:cmdLine,t:normalizePath,t:lowercase"] | |
ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `8' ) [file "/home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "80"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 8)"] [data ""] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "192.168.0.1"] [uri "/projectName/"] [unique_id "17154304293.336548"] [ref ""] | |
时间:2024 年 5 月 11 日 17:08:16 | |
错误码:403(Access denied) | |
客户端 IP:192.168.0.1 | |
规则文件路径:/home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf | |
规则 ID:920350 | |
错误消息:Host header is a numeric IP address | |
严重性:4 | |
规则版本:OWASP_CRS/3.2.0 | |
标签:application-multi、language-multi、platform-multi、paranoia-level/1 | |
主机名:127.0.0.1 | |
请求 URI:/projectName/ | |
请求方法:GET | |
等等。。。 | |
后面几个也是差不多的 |
# 扩展针对指定 url、参数配置白名单:
情况:cas 项目做统一认证,在没有域名的情况下,使用 ip 访问会被误拦截
比如:http://192.168.0.1/cas/login?service=http%3A%2F%2F192.168.0.1%2Fproject2%2Fasb.do%3Fsysno%3D11 被 modsecurity 拦截了
直接访问 http://192.168.0.1/cas/login 是正常的 那么就出现在 service 上,那么就可以针对 uri=/cas/login 和 args=service 做白名单配置
开始:
自己新建一个白名单的配置文件 | |
cd /home/software/nginx-mod/nginx-1.25.5/conf/modsecurity/rules | |
vim custom-whitelist.conf | |
添加: | |
SecRule REQUEST_URI "@beginsWith /cas/login" "id:500001,phase:1,pass,nolog,ctl:ruleRemoveTargetById=949110;ARGS:service" | |
SecRule REQUEST_URI "@beginsWith /cas/logout" "id:500002,phase:1,pass,nolog,ctl:ruleRemoveTargetById=949110;ARGS:service" | |
上述规则表示,当被访问的URL为/cas/login 或者/cas/logout 开头时,选择性的只针对service参数取消ID编号为942100的规则匹配,该次请求的其他参数依旧会被该规则进行匹配校验。 | |
#注意 id 不能重复 | |
#ruleRemoveTargetById=949110 表示删除 949110 编号的校验,因为这边查看了日志发现是这个编号误拦截了 |
# 参考资料
- modsecurity 官方文档
- modsecurity 配置白名单
- 配置 GeoIP 模块来拦截非指定国家的所有 IP
- ModSecurity 规则编写入门教程