必须显式配置请求体读取与缓冲才能使 $request_body 可用:启用 client_body_in_single_buffer on、合理设置 client_body_buffer_size 和 client_max_body_size,并使用 $request_body_base64 避免日志格式破坏,仅在必要 location 限制启用以保障性能与安全。

直接在 log_format 中使用 $request_body 是无效的——Nginx 默认不缓存请求体,该变量在日志格式化阶段始终为空。要实现安全审计所需的报文全留存,必须配合显式读取请求体、启用缓冲,并注意性能与安全边界。
启用 request_body 读取和缓存
Nginx 默认仅在需要时(如 proxy_pass 或某些模块触发)才读取并缓存请求体。审计场景下需强制提前读取,否则 $request_body 不可用。关键配置如下:
- 在对应
location块中添加proxy_buffering off;(若走代理)或更通用的做法:用client_body_buffer_size和client_max_body_size合理设置缓冲上限,避免大文件耗尽内存 - 必须添加
client_body_in_single_buffer on;,确保整个 body 被加载到单块内存中,否则$request_body可能截断或为空 - 搭配
client_body_in_file_only off;(默认值),禁止落盘;若需处理超大 body,可设为clean并配合client_body_temp_path,但审计日志通常不建议依赖临时文件(可靠性与性能下降)
定义支持 $request_body 的 log_format
在 http 块中定义日志格式,注意:$request_body 仅在请求体已读取的前提下才有效:
log_format security_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'req_body:"$request_body"';
⚠️ 注意事项:
- GET 请求无 request body,该字段为空字符串,无需特殊过滤
- 含二进制、换行、控制字符的内容会导致日志解析困难,建议在采集端做 base64 编码(见下一点)
- 敏感字段(如密码、token)不应明文落库,需在日志采集层脱敏,Nginx 层不建议做复杂过滤(性能损耗大且不可靠)
推荐:用 base64 编码保障日志完整性
原始 $request_body 可能含非法字符(如双引号、换行),破坏日志结构。Nginx 1.13.5+ 支持 $request_body_base64 变量,自动 base64 编码且规避特殊字符问题:
log_format security_log_base64 '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'req_body_b64:"$request_body_base64"';
这样既保留完整原始字节,又适配文本日志系统(如 ELK、Splunk),后续可在 SIEM 中解码分析。
性能与安全约束必须明确
全量记录请求体对生产环境是高成本操作,务必限制范围:
- 仅在特定 location(如
/api/、/login)启用,避免全局开启 - 设置
client_max_body_size 2m;防止恶意上传拖垮服务(根据业务调整,一般审计覆盖 JSON 表单足够) - 禁用
large_client_header_buffers等无关缓冲,专注 body 控制 - 日志轮转策略需强化(如
rotate 7+maxsize 100m),防止磁盘打满
不复杂但容易忽略:变量生效的前提是 Nginx 真正读取了 body。没加 client_body_in_single_buffer on,再好的 log_format 也记不到内容。










