📌 第二部分:WAF部署
🤔 什么是 WAF?
WAF,全称 Web Application Firewall(网页应用防火墙),是一种专门保护网站应用层安全的防御系统。
与传统防火墙主要针对 IP、端口不同,WAF 直接分析 HTTP 请求内容,能识别并拦截:
- SQL 注入
- XSS(跨站脚本攻击)
- 文件上传漏洞
- 目录遍历
- WordPress 特有的攻击路径扫描(如 xmlrpc、wp-login、wp-json 枚举)
它像一个「守门员」,替你挡在服务器之前,拦掉大部分恶意请求。
📌 为什么 WordPress 更需要 WAF?
WordPress 是世界上使用最广泛的 CMS 系统,这也意味着它是攻击者重点盯上的目标。
即便你已经做好了 Nginx 安全头、权限配置、禁用路径访问等防护措施,仍然可能因为某个插件漏洞或未知请求被突破。WAF 正是你最后一道主动防御的防火墙。
📌 WAF 的优势是什么?
功能 | 描述 |
---|---|
精准拦截 | 能基于规则分析请求内容,而非仅靠 IP 或端口判断 |
实时防护 | 无需重启服务即可立即生效,规则可热更新 |
攻击可视化 | 可与日志系统配合监控攻击路径、频率、来源 |
可自定义规则 | 可根据你的网站特点定制防护策略,如限制访问 /wp-login.php 等 |
🧰 你的选择:
- ModSecurity + Core Rule Set(CRS):功能强大,开源,适用于 Nginx
- 商业 WAF(如 Cloudflare WAF):可视化面板+智能学习
- 自定义规则拦截(通过 Nginx Lua / Fail2ban + 日志组合)
🛡️ WAF 配置大致步骤:
- 🔧 部署防护模块(如 Nginx + ModSecurity、OpenResty 等)
- 📝 启用并加载基础规则集(如 OWASP CRS)
- ✅ 自定义放行规则,适配业务需求
- 🔄 定期更新规则集,应对新型攻击
📝 小结:
WAF 并不是万能的,但它是网站安全的关键一环。对 WordPress 这样公开暴露、插件繁多的系统而言,它是“能挡下 90% 自动化攻击”的护城河。
编译并安装ModSecurity
用git命令将完整的ModSecurity源码从github上拉取下来
$ cd /usr/local/src
$ sudo git clone --recursive https://github.com/owasp-modsecurity/ModSecurity ModSecurity
安装依赖包,这些包在后续的编译过程中会用到。
$ sudo dnf groupinstall 'Development Tools'
$ sudo dnf install pcre-devel ssdeep-devel libmaxminddb-devel yajl-devel lmdb-devel zlib-devel libcurl-devel libxml2-devel lua-devel jansson-devel openssl-devel pcre2-devel
这些开发包(*-devel
)是在从源代码编译 ModSecurity(尤其是 v3) 时常见的依赖项。它们提供了对应库的头文件和开发接口,ModSecurity 及其依赖组件会根据功能模块需要引用这些库。下面是它们的作用一览:
📦 编译 ModSecurity 所需开发库解释:
开发包 | 作用说明 |
---|---|
pcre-devel | 提供 PCRE(Perl兼容正则表达式) 支持,ModSecurity 使用它进行规则匹配(ModSecurity v2 用得更多)。 |
pcre2-devel | 提供 PCRE2 支持,是 PCRE 的新版实现,ModSecurity v3 支持这类更现代的正则引擎。 |
ssdeep-devel | 用于 模糊哈希(fuzzy hashing) 检测相似内容,可用于检测相似攻击载荷。 |
libmaxminddb-devel | 支持 GeoIP2 功能,通过 IP 查询用户地理位置,有助于规则中基于地域做决策。 |
yajl-devel | 提供 JSON 解析能力(Yet Another JSON Library),ModSecurity 需要解析 JSON 请求体时依赖它。 |
lmdb-devel | 提供 高性能嵌入式数据库 支持,可用于存储缓存、规则状态、IP黑白名单等。 |
zlib-devel | 支持 gzip/zlib 压缩格式的内容处理,比如解压请求体、分析被压缩的数据。 |
libcurl-devel | 支持 ModSecurity 与外部服务进行 HTTP 请求(如远程验证或联动分析)。 |
libxml2-devel | 提供 XML 解析功能,当规则中需要解析或验证 XML 请求体时使用。 |
lua-devel | ModSecurity 支持 Lua 扩展脚本,允许用户用 Lua 编写高级自定义规则逻辑。 |
jansson-devel | 又一个 JSON 库,用于解析 JSON 请求体或结构化数据,某些版本的 ModSecurity 会优先支持它。 |
openssl-devel | 提供 TLS/加密算法支持,ModSecurity 与加密相关的分析(如 HMAC 校验)可能用到它。 |
📌 小结:
- ✅ 大部分是为了让 ModSecurity 能分析复杂请求体结构(如 JSON/XML)、执行正则规则、进行地理/IP匹配或扩展功能(如 Lua 脚本)。
- 🛠️ 缺失这些依赖会导致部分功能无法启用或编译失败。
- 🧩 实际依赖可根据你启用的模块精简,默认全部安装。
$ cd ModSecurity
$ sudo ./build.sh
./build.sh
是一个构建脚本,常见于手动编译项目时。它的作用是自动化执行一系列构建准备步骤,通常比 ./configure
更“高级”,因为它可能还会调用 git
, cmake
, make
, autoconf
, libtool
等工具组合使用。
🔍 通常 ./build.sh
会做的事情有:
- 初始化构建环境
- 运行
git submodule update --init --recursive
- 确保依赖的源码库或子模块同步到位(例如 ModSecurity v3 用到
libinjection
)
- 运行
- 生成 configure 文件
- 如果项目是 autotools 构建体系,它可能会运行:
autoreconf -fiv
- 这一步会创建
configure
脚本,让你后续可以手动执行./configure
。
- 如果项目是 autotools 构建体系,它可能会运行:
- 准备构建系统
- 设置
libtool
,aclocal
,automake
等构建工具用的元文件
- 设置
- 输出提示
- 有些
build.sh
会检查你是否已经安装了必要的*-devel
包,并输出警告信息或退出
- 有些
$ sudo ./configure --with-lmdb
默认情况下,构建过程中会将所有的功能都启用,可是不知道什么原因lmdb需要添加–with-lmdb选项来手动启用它。如果不加这个选项,输出的结果会显示lmdb disabled.
如果添加了–with-lmdb选项仍然显示disabled,那么请执行以下命令后重新执行./configure --with-lmdb
进行新一轮的构建。
$ sudo echo "/usr/lib64" | sudo tee /etc/ld.so.conf.d/lmdb.conf #告诉系统 lmdb 的库文件在 /usr/lib64 目录
$ sudo ldconfig -p |grep lmdb #查看系统中是否已经识别并缓存了 lmdb 的库文件路径。
$ export CFLAGS="-I/usr/include" #设置 C 编译器的头文件搜索路径。
$ export LDFLAGS="-L/usr/lib64" #设置链接器的库文件搜索路径。
./configure
是大多数源代码包中用于准备构建的脚本,它是由 autoconf
工具生成的,主要作用是:
🧠 检测你的系统环境,并为
make
编译生成正确的Makefile
等构建文件。
它主要做这些事:
1️⃣ 检查编译环境是否满足
- 检查编译器(如
gcc
、clang
)是否存在 - 检查必要工具是否安装(如
make
、ar
、ranlib
)
2️⃣ 检查头文件和库
- 会尝试编译一些临时程序,测试是否有对应的头文件和函数:
#include <stdio.h>
是否能找到?malloc()
是否能调用?- 是否链接得到
libpcre
,liblmdb
,libcurl
等库?
- 会生成
config.log
和config.status
用于记录这些测试
3️⃣ 生成配置宏头文件(如 config.h
)
- 里面包含大量宏定义,源码中可以通过条件编译选择不同代码路径。
4️⃣ 生成 Makefile
- 读取
Makefile.in
模板,加上系统测试结果,生成最终可用的Makefile
- 这个文件定义了后续
make
的行为(编译哪些.c
、链接成哪些目标文件)
5️⃣ 根据参数自定义构建
你可以通过传参来自定义配置行为,例如:
示例 | 作用 |
---|---|
--prefix=/usr/local/modsecurity | 安装路径 |
--with-lmdb | 启用某功能 |
--with-pcre=/usr/local/pcre | 指定依赖库路径 |
--disable-ssdeep | 关闭某功能 |
🧾 执行后生成的文件
文件/目录 | 用途 |
---|---|
Makefile | 编译说明 |
config.h | 系统特性宏定义 |
config.status | 当前配置状态 |
config.log | 错误排查日志 |
✅ 总结一句话:
./configure
就是让源代码“适应”你当前系统的工具,它为后续make
准备好所有路径、特性、库依赖,并生成定制化的编译配置。
$ sudo make
$ sudo make install
make
和 make install
是基于 Makefile
的标准构建流程中的两个关键命令,它们是你完成源码编译和安装的最终步骤。
🧱 一、make
的作用
💡 根据
Makefile
的规则编译源码,生成可执行文件、库或目标文件。
🔧 详细来说:
- 调用系统编译器(如
gcc
、clang
)编译.c
文件为.o
文件 - 将多个
.o
目标文件链接成:- 可执行程序(如
modsecurity
) - 动态库(如
libmodsecurity.so
) - 静态库(如
libmodsecurity.a
)
- 可执行程序(如
✅ 最终结果:
- 文件仍然保留在源码目录下(比如
src/
或build/
目录) - 并不会被安装到系统路径
📦 二、make install
的作用
💡 将
make
编译生成的内容复制到系统指定目录,例如/usr/local/bin
、/usr/lib
等。
⚙️ 它通常会做:
- 把可执行程序安装到系统目录(如
/usr/local/bin/modsecurity
) - 把头文件安装到
/usr/local/include
- 把库文件
.so
、.a
安装到/usr/local/lib
- 把文档、配置文件安装到
/usr/local/share
,/etc
ModSecurity安装结束,最终的可执行文件和模块位于/usr/local/modsecurity
。
编译并安装modsecurity-nginx
modsecurity
和 modsecurity-nginx
是两个紧密关联但职责不同的组件,它们共同实现了 WAF(Web 应用防火墙)功能在 Nginx 上的运行。
✅
modsecurity
是核心引擎,modsecurity-nginx
是连接 Nginx 和这个引擎的“适配器”模块。
🔍 两者的关系
项目 | 说明 |
---|---|
modsecurity | 🔧 核心库(libmodsecurity):实现了 WAF 的规则引擎、日志系统、攻击检测等。它是通用的,可以给 Apache、Nginx、甚至嵌入式系统使用。 |
modsecurity-nginx | 🔗 适配模块,让 Nginx 能调用 modsecurity 引擎处理 HTTP 请求,是一个中间层。 |
🔧 安装过程
为了在 Nginx 中使用 WAF,通常流程是:
- ✅ 先编译和安装
modsecurity
(已完成) - ✅ 然后编译
modsecurity-nginx
模块,并在构建 Nginx 时通过--add-module
加进去 - ✅ 在 Nginx 配置文件中启用ModSecurity
📌 如果你只是安装了 modsecurity
而没有 modsecurity-nginx
,Nginx 是无法使用 WAF 功能的。反之也一样:modsecurity-nginx
只是接口,不能单独工作。
在编译modsecurity-nginx之前,需要下载nginx的源码包,用于后续的动态模块编译
$ nginx -v #假设版本号是1.20.1
$ cd /usr/local/src
$ sudo wget http://nginx.org/download/nginx-1.20.1.tar.gz
$ sudo tar -xzf nginx-1.20.1.tar.gz
$ cd nginx-1.20.1/
下载modsecurity-nginx源码,动态编译nginx模块
$ sudo git clone https://github.com/SpiderLabs/ModSecurity-nginx
$ sudo ./configure --with-compat --add-dynamic-module=./ModSecurity-nginx #--with-compat的目的是确保编译的模块与原有的安装兼容,例如原来是通过dnf等包管理器安装的情况
$ sudo make modules #这里无需编译整个nginx,只要编译模块即可
$ sudo cp objs/ngx_http_modsecurity_module.so /usr/share/nginx/modules/
配置规则
下载规则库
$ cd /usr/local/src
$ sudo git clone https://github.com/coreruleset/coreruleset.git #下载规则库
$ cd coreruleset
$ sudo git describe --tags #查看规则库的版本
复制相关文件到nginx目录
$ cd .. #退回到/usr/local/src目录
$ sudo mkdir /etc/nginx/modsecurity
$ sudo cp ModSecurity/modsecurity.conf-recommended /etc/nginx/modsecurity/modsecurity.conf #这个是ModSecurity的核心配置文件
$ sudo cp ModSecurity/unicode.mapping /etc/nginx/modsecurity/unicode.mapping #这个是Unicode映射表
$ sudo cp -r /usr/local/src/coreruleset/rules /etc/nginx/modsecurity/ #复制整个rules目录
$ sudo cp /usr/local/src/coreruleset/crs-setup.conf.example /etc/nginx/modsecurity/crs-setup.conf #规则集初始化配置模板
$ cd /etc/nginx/modsecurity/rules/
$ sudo mv REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
$ sudo mv RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
📄 常见 ModSecurity/CRS 配置文件作用说明
文件名 | 作用说明 |
---|---|
modsecurity.conf-recommended | ModSecurity 官方提供的推荐主配置模板,包含引擎启用、日志格式、检测模式(SecRuleEngine )、请求体限制等核心设置。需重命名为 modsecurity.conf 才生效。 |
unicode.mapping | Unicode 映射表,用于将 HTTP 请求中的编码字符(如 %u002f )还原为实际字符,防止编码绕过攻击。通过 SecUnicodeMapFile 引用,属于 ModSecurity 核心配置之一。 |
crs-setup.conf.example | OWASP CRS 提供的初始化配置模板,用于设置全局规则行为,如检测敏感度(paranoia_level )、阈值(anomaly_score_threshold )、允许方法等。需复制为 crs-setup.conf 才会生效。 |
REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example | 在加载核心规则(900 之后)之前运行的排除规则模板,用于根据 URI、参数、IP 等自定义白名单规则,避免误报。建议在生产环境启用并定制。 |
RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example | 在所有规则执行完毕之后运行的排除规则模板,常用于放行已知业务中的合法响应误报,也可用于记录特定响应行为。同样需要复制并启用。 |
启用modsecurity.conf并添加规则库
$ sudo vim /etc/nginx/modsecurity/modsecurity.conf
SecRuleEngine On #启用ModSecurity引擎
#添加规则库
Include /etc/nginx/modsecurity/crs-setup.conf
Include /etc/nginx/modsecurity/rules/*.conf
在Nginx中启用ModSecurity
$ sudo vim /etc/nginx/nginx.conf
load_module /usr/share/nginx/modules/ngx_http_modsecurity_module.so; #添加在顶部,作为全局配置
#以下部分加在http block内,server块之外,作用于整个http block
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;
重启Nginx
$ sudo systemctl restart nginx.service
检查/var/log/nginx/error.log
日志会发现一共加载多少条规则
[notice] 197072#197072: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/816/0)
被拒绝的例子:
[error] 192055#192055: *51687 [client 51.89.153.66] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:BLOCKING_INBOUND_ANOMALY_SCORE' (Value: `5' ) [file "/etc/nginx/modsecurity/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "222"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [data ""] [severity "0"] [ver "OWASP_CRS/4.13.0-dev"] [maturity "0"] [accuracy "0"] [tag "anomaly-evaluation"] [tag "OWASP_CRS"] [hostname "1.2.3.4"] [uri "/xmlrpc.php"] [unique_id "175006734466.569961"] [ref ""], client: 51.89.153.66, server: www.example.com, request: "POST /xmlrpc.php HTTP/1.1", host: "example.com"
配置SELinux策略
ModSecurity 可能会使用 LuaJIT 来提高性能,因此 Nginx 在启用了 ModSecurity(特别是 OWASP Core Rule Set)时,可能会触发 execmem
访问请求。这是因为 LuaJIT 运行时 需要分配可执行和可写的内存区域,而 SELinux 默认禁止这种行为。你可能会在audit
日志中发现如下的错误信息:
$ sudo sealert -a /var/log/audit/audit.log
#输出如下(省略了部分信息)
SELinux is preventing /usr/sbin/nginx from using the execmem access on a process...
这句话的意思是 SELinux 阻止了 /usr/sbin/nginx
进程在某个进程上执行 execmem
操作。
什么是 execmem?
execmem
(Executable Memory)权限允许进程分配一个 既可写(writable)又可执行(executable) 的内存区域。这种操作可能被用来:
- 运行 JIT(Just-In-Time)编译器(例如 JavaScript 引擎、LuaJIT 等)
- 加载动态代码(如某些模块需要修改自身代码)
- 攻击者利用漏洞执行代码注入(这就是 SELinux 阻止它的原因)
SELinux 提供的解决方案
方案 1:启用 SELinux 允许的 httpd_execmem
boolean
***** Plugin allow_execmem (53.1 confidence) suggests *********************
If you know why nginx needs to map a memory region that is both executable and writable and understand that this is a potential security problem.
Then you can allow the mapping by switching one of the following booleans: httpd_execmem
Do
setsebool -P httpd_execmem 1
解释:
httpd_execmem
SELinux 布尔值 决定是否允许 Nginx(httpd_t 类型) 进程执行execmem
操作。setsebool -P httpd_execmem 1
这个命令可以 永久允许httpd_t
进程执行execmem
。
方案 2:创建一个 SELinux 本地策略模块
***** Plugin catchall (5.76 confidence) suggests **************************
If you believe that nginx should be allowed execmem access on processes labeled httpd_t by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
ausearch -c 'nginx' --raw | audit2allow -M my-nginx
semodule -X 300 -i my-nginx.pp
解释:
ausearch -c 'nginx' --raw | audit2allow -M my-nginx
- 这条命令会从 audit 日志 生成一个允许
nginx
执行execmem
的 SELinux 策略模块。
- 这条命令会从 audit 日志 生成一个允许
semodule -X 300 -i my-nginx.pp
- 这个命令会 安装并加载 这个本地 SELinux 策略模块。
推荐方案
如果你的服务器 专门用于 Nginx + ModSecurity,并且你信任 Nginx 的代码,使用 方法 1(全局启用 httpd_execmem
) 是最简单的解决方案。
如果你的服务器上运行多个 Web 服务,并且你希望 最小化安全风险,建议使用 方法 2(创建本地 SELinux 策略),只对 Nginx 赋权。
如果采用方案2,下面的命令用于列出模块、删除模块操作,用于验证规则是否生效。
$ sudo semodule -l
$ sudo semodule -lfull |grep my-nginx
$ sudo semodule -X 300 -r my-nginx