Nginx 默认不记录 $request_body,需显式触发读取(如 proxy_pass 或 Lua ngx.req.read_body())、配置缓冲参数(client_body_buffer_size/client_max_body_size)、定义带 escape=json 的审计日志格式,并对敏感字段强制脱敏或限长截断,仅在关键路径分级启用。

确保 $request_body 可用且稳定
直接在 log_format 中写 `"$request_body"` 通常会输出空值或“-”,原因在于 Nginx 为性能默认跳过请求体读取。需显式触发:
- 在需要审计的 location 中启用 proxy_pass(如转发到后端 API),这是最常用且可靠的方式;Nginx 在代理前会自动读取并缓存请求体(前提是未超限)
- 设置缓冲参数防止截断:
client_body_buffer_size 128k;和client_max_body_size 1m;(根据业务调整,避免大文件导致 body 被写入临时文件而不可见) - 禁用临时文件缓存:
client_body_in_file_only off;,确保 body 始终驻留内存供日志引用 - 若不用代理,可用 OpenResty 的 Lua 模块:
access_by_lua_block { ngx.req.read_body() }主动读取,再通过$request_body引用
定义带 body 的审计日志格式
仅在必要路径(如 /login、/api/auth、/admin/submit)启用 body 记录,避免全站写入引发性能与隐私风险:
- 在 http 块中定义格式(注意 JSON 转义防注入):
log_format audit_json '{ "@timestamp": "$time_iso8601", "clientip": "$realip_remote_addr", "method": "$request_method", "uri": "$uri", "status": $status, "req_body": "$request_body" }'; - 配合
escape=json更稳妥(Nginx 1.19.3+):
log_format audit_json escape=json '{ "@timestamp": "$time_iso8601", ... "req_body": "$request_body" }'; - 在对应 location 中启用:
access_log /var/log/nginx/auth_audit.log audit_json;
强制脱敏与分级控制
明文记录密码、token、身份证等字段违反安全规范,也易被日志系统误解析。不能依赖后处理,必须前置过滤:
- 用 map + 正则 静态抹除敏感参数(适用于 query 或简单 form-data):
map $args $clean_args { ~*(?:password|token|auth_key|id_card) "" ; default $args; },再在日志中用"args": "$clean_args" - 对 JSON 类型请求体,推荐用 log_by_lua_block 解析并替换敏感 key:
匹配password、access_token等字段,将其值统一替换为"***" - 限制长度防膨胀:
在 Lua 中截取 body 前 1024 字节,或使用substr函数(需编译支持) - 只对特定状态码记录 body,例如仅当
$status >= 400时落盘,聚焦异常行为
替代方案更推荐生产环境采用
纯 Nginx 层记录完整表单存在固有局限:无法解析 multipart、不支持二进制、难以做语义判断。实际审计中建议分层协作:
- Nginx 层只记录元数据:真实 IP、URI、Content-Type、Content-Length、$request_id、响应状态和耗时
- 关键业务逻辑(如登录、支付、权限变更)由后端应用解析表单,提取结构化字段(用户 ID、操作类型、目标资源),脱敏后写入独立审计库
- 所有组件共享
X-Request-ID,实现 Nginx 日志 → 应用日志 → 数据库变更日志的全链路追溯


















