Nginx WAF ModSecurity 配置介绍:构建强大的Web应用防火墙
在当今网络安全威胁日益严峻的环境下,保护Web应用免受攻击是至关重要的。SQL注入、跨站脚本 (XSS)、远程代码执行等攻击手法层出不穷。Web应用防火墙 (WAF) 作为一道重要的防线,能够检查、过滤并阻断恶意HTTP流量,从而显著提升Web应用的安全性。
ModSecurity 是一个广泛使用、功能强大的开源Web应用防火墙引擎。它最初是为 Apache HTTP Server 设计的,但随着其发展,特别是 ModSecurity v3 的发布,它已经成为一个独立的引擎库 (libmodsecurity
),可以通过连接器集成到多种Web服务器中,包括高性能的 Nginx。
将 Nginx 与 ModSecurity 结合,可以充分利用 Nginx 的高性能和可扩展性,同时拥有 ModSecurity 提供的灵活且强大的安全规则处理能力。本文将详细介绍如何在 Nginx 环境下配置和使用 ModSecurity,包括安装、核心配置、规则集应用、日志分析以及性能调优等方面。
1. 为什么选择 Nginx + ModSecurity?
在深入配置之前,理解为什么这是一个流行的选择很重要:
- Nginx 的高性能: Nginx 以其轻量级、高并发处理能力和优秀的性能著称,尤其适合作为反向代理或负载均衡器。将其与 WAF 集成,可以在不牺牲过多性能的情况下增强安全防护。
- ModSecurity 的灵活性与强大功能: ModSecurity 提供了基于规则的检测引擎,支持丰富的变量、操作符和动作,可以编写高度定制化的规则来匹配各种攻击模式。
- 开源和社区支持: 两者都是流行的开源项目,拥有庞大的社区支持,这意味着可以轻松找到文档、解决方案以及预先编写好的规则集(如 OWASP Core Rule Set)。
- ModSecurity v3 的现代化架构: ModSecurity v3 将核心处理逻辑与Web服务器解耦,通过独立的连接器实现集成,这使得在 Nginx 中部署更加清晰和稳定。
2. Nginx 与 ModSecurity v3 的安装与集成
ModSecurity v3 (libmodsecurity) 需要一个与特定Web服务器交互的连接器。对于 Nginx,这个连接器通常被称为 nginx-modsecurity
。在 Nginx 中集成 ModSecurity v3 通常需要从源码编译 Nginx 并将 nginx-modsecurity
作为动态模块或静态模块添加。推荐使用动态模块,因为它允许在不重新编译整个 Nginx 的情况下加载或卸载模块。
以下是大致的编译步骤(以 Linux 为例,具体命令可能因发行版和版本而异):
步骤 1: 安装依赖库
ModSecurity v3 依赖于一些库,例如 libxml2, libyajl, libcurl, gd, 等。具体依赖请参考 ModSecurity 的官方文档。
“`bash
以 Debian/Ubuntu 为例
sudo apt update
sudo apt install build-essential autoconf automake libtool libcurl4-openssl-dev libxml2-dev libpcre3-dev libgeoip-dev liblmdb-dev zlib1g-dev libssl-dev pkg-config
“`
步骤 2: 下载 ModSecurity v3 核心 (libmodsecurity
) 和 Nginx 连接器 (nginx-modsecurity
)
“`bash
克隆 libmodsecurity 仓库
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 –enable-dynamic –enable-standalone-module # –enable-standalone-module 可以用于测试,但通常只用 –enable-dynamic
make -j$(nproc)
这里通常不需要 make install,因为 Nginx 编译时会引用其源码
cd .. # 回到上一级目录
克隆 nginx-modsecurity 连接器仓库
git clone –depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
“`
步骤 3: 下载 Nginx 源码并编译
下载与你计划部署版本一致的 Nginx 源码。
“`bash
下载 Nginx 源码,例如 1.24.0
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar zxvf nginx-1.24.0.tar.gz
cd nginx-1.24.0
编译 Nginx,将 nginx-modsecurity 作为动态模块添加
请保留你原有的 Nginx 编译参数,这里只添加 modsecurity 模块
./configure –prefix=/etc/nginx \
–sbin-path=/usr/sbin/nginx \
–modules-path=/usr/lib/nginx/modules \
–conf-path=/etc/nginx/nginx.conf \
–error-log-path=/var/log/nginx/error.log \
–http-log-path=/var/log/nginx/access.log \
–pid-path=/var/run/nginx.pid \
–lock-path=/var/run/nginx.lock \
–http-client-body-temp-path=/var/cache/nginx/client_temp \
–http-proxy-temp-path=/var/cache/nginx/proxy_temp \
–http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
–http-unix-domain \
–with-compat \
–with-file-aio \
–with-threads \
–with-http_ssl_module \
–with-http_stub_status_module \
–with-http_realip_module \
–with-http_auth_request_module \
–with-http_addition_module \
–with-http_gzip_static_module \
–with-http_sub_module \
–with-stream \
–with-stream_ssl_module \
–with-stream_realip_module \
–add-dynamic-module=../ModSecurity-nginx # 注意这里的路径指向连接器源码目录
make -j$(nproc)
sudo make install # 或者只 make modules 然后手动拷贝 module 文件到 modules 目录
“`
步骤 4: 载入 ModSecurity 动态模块
编辑 Nginx 主配置文件 nginx.conf
,在 http
块或顶层添加加载模块的指令:
“`nginx
/etc/nginx/nginx.conf
load_module modules/ngx_http_modsecurity_module.so;
http {
# … 其他配置 …
}
“`
步骤 5: 获取 ModSecurity 核心配置文件
从 ModSecurity 源码目录或仓库中获取示例配置文件并复制到 Nginx 配置目录下:
“`bash
从 ModSecurity 源码目录复制
sudo cp ../ModSecurity/modsecurity.conf-recommended /etc/nginx/modsecurity.conf
或者从 github 下载
wget https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended -O /etc/nginx/modsecurity.conf
“`
至此,ModSecurity 模块已经被编译并加载到 Nginx 中,接下来是配置 ModSecurity 本身。
3. ModSecurity 核心配置 (modsecurity.conf
)
modsecurity.conf
是 ModSecurity 引擎的主配置文件,它定义了引擎的行为、加载哪些规则以及一些全局设置。从 modsecurity.conf-recommended
复制的文件是一个很好的起点,但需要根据实际情况进行调整。
以下是一些关键的配置指令:
-
SecRuleEngine On | Off | DetectionOnly
On
: ModSecurity 完全启用,根据规则执行动作(包括阻断)。Off
: ModSecurity 完全关闭,不进行任何检查。DetectionOnly
: ModSecurity 只进行规则匹配和日志记录,但不执行任何阻断动作。这在初次部署或调试规则时非常有用,可以观察哪些规则会被触发而不会影响正常流量。
通常在生产环境设置为
On
,在测试/调试阶段设置为DetectionOnly
。 -
Include /path/to/rules/*.conf
这个指令用于加载 ModSecurity 规则文件。你可以使用它来加载 OWASP Core Rule Set (CRS) 或自定义的规则文件。通常会包含多个Include
指令来加载不同的规则集。 -
SecRequestBodyAccess On | Off
控制 ModSecurity 是否应该访问请求体。对于需要检查 POST 参数、上传文件内容的规则(如 SQLi、XSS 检查),必须启用此选项。大多数情况下应设置为On
。 -
SecResponseBodyAccess On | Off
控制 ModSecurity 是否应该访问响应体。这用于检测响应中的敏感信息泄露或恶意内容注入。如果启用,可能会对性能产生较大影响,且需要配置SecResponseBodyMimeType
来指定需要检查的MIME类型。通常默认为Off
。 -
SecAuditLog /path/to/audit.log
指定 ModSecurity 的审计日志文件路径。审计日志记录了 ModSecurity 处理的每个事务(或匹配规则的事务),是分析攻击和调试规则的关键。 -
SecAuditLogParts ABIFHZ
控制审计日志包含哪些部分。常用的部分有:A
: 审计日志头部。B
: 请求头部。C
: 请求体 (如果SecAuditLogRequestBody
启用)。D
: 审计日志分隔符。E
: 响应体 (如果SecAuditLogResponseBody
启用)。F
: 审计日志尾部。G
: 告警信息 (匹配规则的详细信息)。H
: 响应头部。I
: 倒置的请求和响应头部 (用于调试)。J
: 请求体和响应体的JSON表示。K
: 所有匹配的规则ID。Z
: 审计日志的页脚。
推荐使用
ABIFHZ
或ABCEFHIKZ
以获取详细信息进行分析。 -
SecAuditLogRelevantStatus "^(?:5|4\\d{2})"
指定哪些HTTP状态码的响应应该被记录到审计日志中。默认值通常只记录错误(4xx 和 5xx),你可以根据需要修改,例如记录所有被 ModSecurity 阻断的请求。 -
SecAuditLogType Serial | Concurrent
指定审计日志的写入方式。Serial
: 所有事务顺序写入一个文件。简单,但高并发下可能成为瓶颈。Concurrent
: 每个事务写入一个单独的文件,文件名包含事务ID,写入效率更高,但文件数量多,清理和分析需要额外工具。通常推荐Concurrent
。
-
SecAuditLogStorageDir /path/to/audit_storage
当SecAuditLogType
为Concurrent
时,指定临时存储审计日志文件的目录。最终文件会移动到SecAuditLog
指定的位置。 -
SecDefaultAction phase:N,action1,action2,...
定义在没有指定动作时,规则匹配后默认执行的动作。通常用于设置规则的默认破坏性动作和日志级别。例如:
SecDefaultAction "phase:2,deny,log,auditlog"
表示在请求体处理阶段,如果规则匹配但未指定动作,则默认拒绝请求、记录到错误日志和审计日志。 -
SecRule ARGS "@detectXSS" "id:1000,deny,log"
这是一个典型的 ModSecurity 规则示例(后面会详细介绍规则语法)。
在配置 modsecurity.conf
时,一个常见的做法是保持核心配置文件的简洁,主要用于设置全局参数、加载规则集(如 CRS)和自定义规则文件。
“`apache
/etc/nginx/modsecurity.conf
SecRuleEngine On
加载 ModSecurity v3 推荐的基本配置
Include modsecurity.conf-recommended
加载 OWASP Core Rule Set (CRS)
请确保 CRS 文件路径正确
Include /etc/nginx/crs-rules/CRS-SETUP-REQUEST.conf
Include /etc/nginx/crs-rules/rules/*.conf
Include /etc/nginx/crs-rules/CRS-SETUP-RESPONSE.conf
加载自定义规则
Include /etc/nginx/custom-rules/*.conf
审计日志配置
SecAuditLog /var/log/nginx/modsecurity_audit.log
SecAuditLogParts ABIFHZ
SecAuditLogRelevantStatus “^(?:5|4\d{2})”
SecAuditLogType Concurrent
SecAuditLogStorageDir /var/log/nginx/modsecurity_audit_temp
其他常用设置
SecRequestBodyAccess On
SecResponseBodyAccess Off # 默认关闭以提高性能
设置默认动作(可选,CRS 通常有自己的默认动作)
SecDefaultAction “phase:2,deny,log,auditlog”
“`
4. 在 Nginx 配置文件中启用 ModSecurity
在 Nginx 的虚拟主机 (server
) 或特定路径 (location
) 中启用 ModSecurity:
“`nginx
http {
# … other http configs …
modsecurity on; # 全局启用 ModSecurity,也可以放在 server 或 location 中
server {
listen 80;
server_name your_domain.com;
# 可以在 server 块中控制 ModSecurity
# modsecurity on; # 在此 server 块启用
# modsecurity off; # 在此 server 块禁用
# modsecurity_rules_file /path/to/server_specific_modsecurity.conf; # 使用单独的规则文件
location / {
# modsecurity on; # 在此 location 启用
# modsecurity off; # 在此 location 禁用
# modsecurity_rules 'SecRuleEngine DetectionOnly'; # 在此 location 临时设置为检测模式
# modsecurity_rules 'Include /etc/nginx/modsecurity.conf'; # 在 location 中加载主规则文件
# 关键:加载 ModSecurity 配置
modsecurity_rules_file /etc/nginx/modsecurity.conf;
proxy_pass http://backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# ... 其他 proxy 配置 ...
}
location /admin {
# 针对特定路径可以有不同的 ModSecurity 配置
modsecurity on; # 确保管理路径开启 WAF
modsecurity_rules_file /etc/nginx/modsecurity_admin.conf; # 可能加载针对管理后台的额外规则
proxy_pass http://admin_backend;
}
location /public/static/ {
# 静态文件通常不需要 WAF 检查,可以禁用以提高性能
modsecurity off;
alias /var/www/html/static/;
}
}
}
“`
modsecurity on;
和 modsecurity_rules_file /path/to/config;
是在 Nginx 中启用和指定 ModSecurity 配置文件的主要方式。modsecurity_rules
指令允许直接在 Nginx 配置中写入 ModSecurity 规则或指令,但不推荐用于包含大量规则,主要用于简单的临时调整或测试。
5. OWASP Core Rule Set (CRS)
OWASP CRS 是 ModSecurity 最常用的规则集,它提供了一套通用的、旨在检测各种常见Web漏洞的规则。CRS 3.x 版本引入了异常评分 (Anomaly Scoring) 模式,而不是传统的“立即阻断”。
异常评分模式的工作原理:
- 每个触发的规则都会为当前请求增加一个“异常分数”。不同严重级别的规则增加的分数不同(例如,信息性规则增加较低分数,高危规则增加较高分数)。
- 请求处理完毕后,ModSecurity 会检查总的异常分数。
- 如果总分数超过预设的阈值,请求才会被阻断。
这种模式的优点是可以减少误报,因为单个规则触发不一定意味着恶意,只有多个规则触发或触发了非常严重的规则才可能指示攻击。
部署 CRS:
- 从 OWASP CRS GitHub 仓库下载最新版本。
- 将规则文件(
rules
目录下的.conf
文件)和配置设置文件 (crs-setup.conf.example
或CRS-SETUP-REQUEST.conf
,CRS-SETUP-RESPONSE.conf
) 复制到 Nginx 可以访问的目录,例如/etc/nginx/crs-rules/
。 - 将
crs-setup.conf.example
复制为CRS-SETUP-REQUEST.conf
或类似名称,并根据需要编辑其中的配置,例如设置异常分数阈值 (tx.anomaly_score_threshold
) 和默认阻断动作 (tx.blocking_paranoia_level
)。 - 在
modsecurity.conf
中使用Include
指令加载 CRS 规则文件(通常按顺序加载 setup -> rules -> response setup)。
“`apache
/etc/nginx/modsecurity.conf
… 其他配置 …
OWASP CRS Setup (调整阈值等)
Include /etc/nginx/crs-rules/CRS-SETUP-REQUEST.conf
OWASP CRS Rules (核心规则文件)
Include /etc/nginx/crs-rules/rules/*.conf
OWASP CRS Response Setup (可选,用于响应阶段规则)
Include /etc/nginx/crs-rules/CRS-SETUP-RESPONSE.conf
… 自定义规则 Include …
“`
CRS 的配置选项很多,例如 paranoia level (偏执等级,影响规则的严格程度),检查哪些变量等等。仔细阅读 CRS 官方文档是正确配置 CRS 的关键。
6. ModSecurity 规则语法 (SecRule)
ModSecurity 的核心是规则。理解规则语法对于编写自定义规则和调试现有规则至关重要。基本语法结构如下:
apache
SecRule VARIABLES OPERATOR ACTIONS
SecRule
: 规则指令关键字。VARIABLES
: 要检查的请求或响应部分。可以是单个变量或多个变量的列表。- 常用变量:
ARGS
(所有请求参数),ARGS_NAMES
(参数名),ARGS_GET
,ARGS_POST
,REQUEST_URI
,REQUEST_FILENAME
,REQUEST_METHOD
,REQUEST_HEADERS
(所有请求头),REQUEST_HEADERS:Host
,REQUEST_BODY
,REMOTE_ADDR
,HTTP_USER_AGENT
,RESPONSE_BODY
,RESPONSE_STATUS
等。 - 可以使用集合变量,如
ARGS|XML:/*|!REQUEST_HEADERS:Referer
表示检查所有参数、XML内容,但不检查 Referer 头。
- 常用变量:
OPERATOR
: 定义如何匹配变量的内容。操作符通常以@
开头。- 常用操作符:
@rx
(正则表达式),@streq
(字符串完全相等),@contains
(字符串包含),@detectSQLi
(检测SQL注入),@detectXSS
(检测XSS),@validateByteRange
(验证字节范围),@pmFromFile
(从文件匹配模式列表) 等。
- 常用操作符:
ACTIONS
: 当规则匹配时要执行的一个或多个动作,用逗号分隔。- 非破坏性动作 (Non-disruptive):
log
: 记录到错误日志。auditlog
: 记录到审计日志。pass
: 跳过当前规则集的剩余规则,继续处理请求。allow
: 允许请求通过,跳过所有剩余规则。severity:N
: 设置规则的严重级别 (0-7)。msg:'message'
: 设置审计日志中的消息。id:N
: 设置规则的唯一ID。强烈建议为每条规则设置唯一的ID (大于1000000以避免与CRS冲突)。tag:'tag_name'
: 为规则添加标签,用于分类和搜索。phase:N
: 指定规则执行的阶段 (1-5)。setvar:variable=value
: 设置一个内部变量的值。chain
: 将下一条规则链接到当前规则,只有当两条(或多条链式规则)都匹配时,整个规则链才算匹配。
- 破坏性动作 (Disruptive):
deny
: 拒绝请求(返回403 Forbidden)。drop
: 直接断开连接。redirect:url
: 将请求重定向到指定URL。status:N
: 返回指定的HTTP状态码。
- 非破坏性动作 (Non-disruptive):
示例规则:
“`apache
阻止来自特定IP地址的请求
SecRule REMOTE_ADDR “@streq 192.168.1.100” “id:1000001,phase:1,deny,log,msg:’Blocked specific IP address'”