全量审计不能依赖 ngx_http_proxy_module 内置变量——因其不提供 $request_body、原始 header 字节、完整 URI 参数等关键字段;真正可行路径需分层补足:C 模块捕获原始请求头、mirror 模块镜像 POST 内容、共享内存实现行为分析。

直接用 ngx_http_proxy_module 的“内置变量”做全量审计是行不通的——它本身不提供请求体($request_body)、原始 header 字节、完整 URI 参数或客户端行为上下文等关键审计字段。所谓“proxy 变量”,其实是代理场景中被透传或动态生成的辅助字段,用于控制转发逻辑,不是为审计设计的。
哪些 proxy 变量能用?用在哪?
这些变量在日志或条件判断中可安全使用,但仅反映代理链路中的中间状态:
-
$proxy_host和$proxy_port:记录你配的后端地址,可用于确认路由是否符合预期,但无法验证实际发了什么数据 -
$proxy_add_x_forwarded_for:拼接后的 IP 链,适合排查路径,但易被伪造,不能作为可信来源依据 -
$upstream_addr和$upstream_status:知道连了谁、返回啥状态,但看不到请求内容本身 -
$upstream_http_*:只能取响应头字段(如$upstream_http_x_ratelimit_remaining),对请求审计无直接帮助
为什么$request_body不能靠proxy模块“启用”?
$request_body 不是 proxy 模块定义的变量,也不受其控制。它的可用性取决于两个硬性前提:
- 请求体已被 Nginx 主动读入内存(通常只在
proxy_pass、fastcgi_pass等指令触发时发生) - 且未超出
client_body_buffer_size缓冲区;一旦写入临时文件,该变量即为空
即便满足,它仍只保留已缓存部分,无法保证完整、不截断、不乱码,更不支持字段级脱敏或原始字节还原。
真正可行的全量审计路径
要实现可靠审计,必须跳出变量依赖,分层补足能力:
-
原始请求头审计:必须写 C 模块,在
NGX_HTTP_POST_READ_PHASE遍历r->headers_in.headers链表,获取未归一化字节流;动态模块或 Lua 无法拿到原始大小写/空格/重复字段 -
POST 内容捕获:用
mirror模块异步镜像请求到审计服务,避免阻塞主流程;或结合log_by_lua_block解析 JSON/form-data 并脱敏,但需预装 Lua 模块且有性能边界 -
行为与上下文分析:用共享内存(
ngx_shm_zone_t)+ 原子计数器构建滑动窗口,统计 UA 变更频次、Referer 合法性、IP 请求密度等,这在 access_phase 才能实时拦截
别踩的坑
常见误操作会带来隐性风险:
- 在
log_format里直接写$request_body:导致大包截断、磁盘打满、敏感字段明文落盘 - 用
proxy_set_header X-Body "$request_body"转发:body 可能为空,且后端未必解析,纯属误导 - 依赖
$http_x_forwarded_for做访问控制:header 可被任意构造,必须配合$realip_remote_addr或 PROXY 协议字段 - 认为开启
proxy_buffering off就能“看到全部流量”:这只是关闭响应缓冲,对请求体审计毫无作用


















