默认情况下Nginx的$request_body变量在访问日志中不可用,需显式配置代理指令或Lua模块强制读取,并通过map匹配路径、Lua脱敏字段、合理设置缓冲参数后,方可安全记录敏感接口请求体。

默认情况下,Nginx 的 $request_body 变量在访问日志中不可用,因为请求体(request body)通常不会被读取或缓存——尤其当请求未被代理、未触发 Lua 脚本、或未启用相关模块时,该变量为空。要审计高危敏感接口的入参报文,必须主动触发 Nginx 对请求体的读取,并将其安全、可控地记录到日志中。
启用 request_body 记录的前提条件
Nginx 默认跳过请求体读取以提升性能,因此需显式配置才能获取 $request_body:
- 使用
proxy_pass或fastcgi_pass等代理指令时,Nginx 会自动读取请求体(但仅限于非 GET/HEAD 请求); - 若后端不代理(如静态服务),需通过
lua-resty-request-body(OpenResty)或ngx_http_realip_module配合自定义逻辑强制读取; -
必须设置
client_max_body_size和client_body_buffer_size,避免因体过大导致截断或 413 错误; - 对 POST/PUT/PATCH 等含 body 的方法启用日志,GET 请求无 body,
$request_body恒为空字符串。
安全记录敏感参数的推荐方式
直接记录完整 $request_body 存在风险:可能泄露密码、token、身份证号等明文信息,也易被日志系统误捕获。应按需脱敏或条件记录:
- 只对特定路径(如
/api/v1/login、/api/user/bind)开启 body 日志,避免全量记录; - 使用
map指令标记高危接口,再结合log_format动态控制是否输出$request_body; - 借助 OpenResty 的 Lua 脚本做字段级过滤(例如只记录
username和action,剔除password、id_card); - 日志写入前进行基础脱敏(如手机号中间 4 位替换为
****),可使用 Lua 的string.gsub实现。
实际可用的 Nginx 配置片段示例
以下为最小可行配置(基于 OpenResty,支持 JSON 解析与字段提取):
http {
map $request_uri $log_body {
~^/api/v1/(login|bind|pay) "1";
default "";
}
<pre class="brush:php;toolbar:false;">log_format audit '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_body';
server {
location ~ ^/api/v1/(login|bind|pay) {
# 强制读取并缓存 request body(最大 1MB)
client_max_body_size 1m;
client_body_buffer_size 128k;
client_body_in_single_buffer on;
# 使用 Lua 提取并脱敏关键字段
access_by_lua_block {
local json = require "cjson"
local req_body = ngx.var.request_body
if req_body and #req_body > 0 then
local ok, data = pcall(json.decode, req_body)
if ok and type(data) == "table" then
if data.password then data.password = "******" end
if data.id_card then data.id_card = string.sub(data.id_card, 1, 3) .. "****" .. string.sub(data.id_card, -4) end
ngx.var.request_body = json.encode(data)
end
end
}
access_log /var/log/nginx/audit.log audit if=$log_body;
proxy_pass http://backend;
}
}}
注意事项与替代方案
生产环境不建议长期全量记录原始请求体,应结合审计目标选择更稳妥的方式:
- 日志轮转与权限管控:确保
audit.log文件属主为专用用户,禁止 web 进程直接读写; - 考虑用 WAF(如 ModSecurity)替代 Nginx 原生方案——它内置规则引擎和字段提取能力,更适合敏感参数审计;
- 若仅需校验而非记录,可用 Nginx + Lua 做实时拦截(如检测
"password":"123456"并返回 400); - 注意 HTTPS 流量下,Nginx 作为 TLS 终结点才能看到明文 body;若用直通模式(TLS passthrough),则无法获取。
不复杂但容易忽略:能拿到 $request_body 不等于应该记录它,重点是“为什么记”和“怎么安全地记”。











