Amh面板Apache2.4编译安装ModSecurity2.9.8

无数失败踩坑记录实现网站访问日志超详细记录

Posted by 浅唱 on March 27, 2025

前言

测试 NapCat Bot 机器人时,由于 php 代码调用接口复杂,NapCat 本身没有响应日志,只记录请求参数,响应只显示 JSON 解析报错,虽然可以抓包实现,但还是想在服务端设置详细的日志记录,便于分析问题。
ModSecurity 对 Apache 的支持仅到 2.9.x 版本,3.0.x 版本需要连接器,但我无法编译成功,且该连接器处于不稳定状态,官方不建议用于生产环境。

环境

操作系统:Ubuntu 22.04
集成环境:AMH 面板 7.2 Apache 2.4

项目地址

https://github.com/owasp-modsecurity/ModSecurity

编译安装

wget https://github.com/owasp-modsecurity/ModSecurity/releases/download/v2.9.8/modsecurity-v2.9.8.tar.gz # 当前 2.9.8 版本为 2.9.x 的最新版本
tar -xzvf modsecurity-v2.9.8.tar.gz #解压
cd modsecurity-v2.9.8
./autogen.sh
./configure --with-apxs=/usr/local/apache-2.4/bin/apxs --with-apr=/usr/local/apache-2.4/bin --with-apu=/usr/local/apache-2.4/bin #这里踩了好多坑
# 首先apx指定apache的apxs可执行文件路径
# apr和apu则apr-1-config和apu-1-config的目录路径,死活找到lib里面的apr.exp和apu.exp都是错的
# 理论上目录路径或者可执行文件路径应该都是可以的,自行尝试下,本次使用目录路径configure通过
make
make install # 编译安装之后会自动将文件移动到apache模块目录里面
chmod 755 /usr/local/apache-2.4/modules/mod_security2.so # 但权限与其他文件不同,为了保持一致,手动修改一下权限

/usr/local/apache-2.4/conf/httpd.conf中加载模块

LoadModule unique_id_module modules/mod_unique_id.so #内置的模块,被依赖,需要先加载
LoadModule security2_module modules/mod_security2.so
Include /usr/local/apache-2.4/conf/mod_security.conf # 引入自定义的配置文件,单独创建方便管理

创建自定义配置文件/usr/local/apache-2.4/conf/mod_security.conf内容如下

SecAuditEngine RelevantOnly
SecRequestBodyAccess On
SecResponseBodyAccess On
SecAuditLogRelevantStatus "^(?!.*204)"
SecDebugLogLevel 0
SecAuditLogParts ABCDEFHZ
SecAuditLogStorageDir /tmp/modsecurity/
SecAuditLogType Concurrent
SecDebugLog /tmp/modsecurity/modsec_debug.log
SecAuditLog /tmp/modsecurity/modsecurity.log
#SecAuditLogType Serial

可用的 SecAuditLogParts:

A:审核日志标头(必填)。
B:请求头。
C:请求正文(仅当请求正文存在且 ModSecurity 配置为拦截它时才存在。这需要将 SecRequestBodyAccess 设置为 on)。
D:保留用于中间响应头;尚未实现。
E:中间响应正文(仅当 ModSecurity 配置为拦截响应正文,并且审计日志引擎配置为记录它时才存在。拦截响应正文需要启用 SecResponseBodyAccess)。中间响应正文与实际响应正文相同,除非 ModSecurity 拦截了中间响应正文,在这种情况下,实际响应正文将包含错误消息(Apache 默认错误消息或 ErrorDocument 页面)。
F:最终响应头(不包括 Date 和 Server 头,它们总是由 Apache 在内容分发的后期添加)。
G:保留给实际的响应体;尚未实现。
H:审计日志尾部。
I:此部件是部件 C 的替代部件。在所有情况下,它将记录与 C 相同的数据,除非使用 multipart/form-data 编码。在这种情况下,它将记录一个虚假的 application/x-www-form-urlencoded 正文,其中包含有关参数的信息,但不包含有关文件的信息。如果您不想在审计日志中存储 (通常是大) 文件,这将非常方便。
J:此部分包含有关使用 multipart/form-data 编码上传的文件的信息。
K:此部分包含按匹配顺序匹配的每个规则的完整列表(每行一个)。这些规则是完全限定的,因此将显示继承的作和默认运算符。从 v2.5.0 开始支持。
Z:最终边界,表示条目的结束(必填)。

不论 SecAuditLogTypeConcurrent 还是 Serial 必有 SecAuditLog 条目 ,为 Concurrent 时还需要有 SecAuditLogStorageDir 条目

  • 其中当 SecAuditLogTypeSerialSecAuditLog 会记录日志的详细信息,对权限没有要求,会以 root 写入
  • 其中当 SecAuditLogTypeConcurrentSecAuditLog 会记录日志的简要信息,对权限没有要求,会以 root 写入

详细信息则记录到 www 目录下,每个条目一个文件,按时间分类

  • SecAuditLogStorageDir要求父目录有 x 权限 即 /tmp 目录,否则 Apache 进程无法进入该目录,即便子目录是 777 ,本目录有 wx 权限 即 /tmp/modsecurity 目录,模块会自动创建 www 目录,直接修改所有者更为方便

因此,创建日志目录并修改所有者

mkdir /tmp/modsecurity # 创建日志目录
chown www:www /tmp/modsecurity # 修改所有者
apache amh apache restart # 重启或者重载 apache

至此,Apache2.4 ModSecurity2.9.8 编译安装完成,可以正常使用。

2025.04.10

今天由于代码问题想利用这个工具查看报错信息,却发现日志里面没有请求体和响应体,经过 ChatGPT 的解答发现有如下默认值导致的:

  1. 默认情况下,ModSecurity 将使用 URLENCODED 和 MULTIPART 处理器分别处理 application/x-www-form-urlencoded 和 multipart/form-data 主体。还支持其他两个处理器:JSON 和 XML,但它们从不自动使用。
    相反,您必须通过在 REQUEST_HEADERS 处理阶段放置一些规则来告诉 ModSecurity 去使用它。在将请求主体作为 XML 处理之后,您将能够使用与 XML 相关的功能来检查它。
    参考:ctl 动作
  2. 默认情况下,ModSecurity 只记录 text/\* 类型响应体,如果你需要记录 application/json、application/xml 等内容类型:

    SecResponseBodyMimeType text/plain text/html text/xml application/json application/xml
    

    参考:SecResponseBodyMimeType 指令

  3. 关于 nolog 动作 ,文档里有一句话尽管nolog也意味着noauditlog,但您可以使用nolog,auditlog覆盖前者,即不记录错误日志,但记录审计日志。,但实际上配置文件中的SecAuditLogRelevantStatus "^(?!.*204)"会覆盖掉 nolog,可以看到匹配规则中

    SecRule "REQUEST_HEADERS:Content-Type" "@rx application/json" "phase:1,auditlog,id:2,t:none,pass,nolog,ctl:requestBodyProcessor=JSON"
    

auditlog字样,因此不需要在动作中操作auditlog,否则所有匹配到的动作会按照规则进行操作,又覆盖掉SecAuditLogRelevantStatus的正则规则

  1. 在我编译的模块中,SecAuditLogParts即便开启了所有可用的选项日志中也仅有ABCEHKZ这几个部分,DG 本来就没有,没有 IJF 不知道是什么问题

因此 最终的配置文件为:

SecAuditEngine RelevantOnly # 开启audit规则
SecRequestBodyAccess On # 开启请求体处理
SecResponseBodyAccess On # 开启响应体处理
SecAuditLogRelevantStatus "^(?!.*204)" # 正则匹配不记录 204 状态码的请求
SecDebugLogLevel 0 # 调试日志
SecAuditLogParts ABIJDEFGHKZ # 审计日志部分
SecRuleEngine On # 开启规则引擎
SecRule REQUEST_BODY "@rx .*" "id:1,phase:2,pass,nolog,t:none"  # 匹配所有请求体 即使为空
SecRule REQUEST_HEADERS:Content-Type "application/json" "id:2,phase:1,t:none,pass,nolog,ctl:requestBodyProcessor=JSON" # 匹配 json 请求体,并调用JSON处理器进行处理
SecResponseBodyMimeType text/plain text/html text/xml application/json application/xml # 设置处理的响应体类型
SecAuditLogType Concurrent # 设置日志类型 多文件
#SecAuditLogType Serial # 设置日志类型 单文件
SecAuditLogStorageDir /tmp/modsecurity/ # 设置日志存储目录 多文件有效 会在目录下建立www目录存储日志
SecDebugLog /tmp/modsecurity/modsec_debug.log # 输出调试日志
SecAuditLog /tmp/modsecurity/modsecurity.log # 记录单条日志 多文件会记录简要信息帮助索引到www目录下的日志文件