
在 Nginx 中实现符合 JSON 规范的审计日志,核心是通过 log_format 指令定义结构化日志格式,并配合 access_log 启用输出。关键在于正确转义双引号、处理空格与特殊字符、确保字段值合法(如字符串加引号、数字不加引号),同时避免因变量为空导致 JSON 格式损坏。
定义合规的 JSON 日志格式
Nginx 原生不支持 JSON 编码,需手动拼接字符串。所有字符串字段必须用双引号包裹,键名和字符串值中的双引号需用反斜杠转义;数值型变量(如 $status、$body_bytes_sent)可不加引号,但为统一性和解析安全,建议统一按字符串处理(即加引号并转义)。
示例(含常见审计字段):
log_format json_audit escape=json ‘{‘ ‘"time_local":"$time_local",’ ‘"remote_addr":"$remote_addr",’ ‘"x_forwarded_for":"$http_x_forwarded_for",’ ‘"request_method":"$request_method",’ ‘"request_uri":"$request_uri",’ ‘"status":$status,’ ‘"body_bytes_sent":$body_bytes_sent,’ ‘"http_referer":"$http_referer",’ ‘"http_user_agent":"$http_user_agent",’ ‘"request_time":$request_time,’ ‘"upstream_response_time":"$upstream_response_time",’ ‘"upstream_addr":"$upstream_addr"’ ‘}’;
注意:escape=json 是 Nginx 1.11.8+ 的关键参数,它会自动对变量值中的双引号、反斜杠、控制字符等做 JSON 转义,大幅降低手写转义出错风险。没有该参数时,需自行用 $escap… 变量或 Lua 模块补救。
启用 JSON 日志并写入文件或 syslog
在 http、server 或 location 块中引用该格式:
写入本地文件(推荐用于调试和中小流量):access_log /var/log/nginx/audit.json json_audit;转发至远程 syslog(适合集中审计):access_log syslog:server=192.168.1.100:514,facility=local7,tag=nginx-audit json_audit;
若使用 systemd-journald,也可通过 syslog 协议接入,便于与 SIEM 工具(如 ELK、Splunk)对接。
增强审计完整性:捕获请求体与响应头(谨慎使用)
标准变量无法直接记录请求体($request_body)或响应头($sent_http_*),需额外配置:
记录请求体需开启 client_body_in_file_only on 或使用 lua-resty-logger-socket 等模块,但注意性能与隐私风险(如密码、token); 记录自定义响应头(如 X-Request-ID)可用 $sent_http_x_request_id; 记录上游服务返回的状态码(非 Nginx 自身状态)可用 $upstream_http_x_backend_status(需后端配合输出)。
不建议在高并发场景下无条件记录请求体,应结合条件日志(if=$condition)仅对特定路径或错误状态启用。
验证与排错要点
生成的日志必须每行一个合法 JSON 对象(JSON Lines 格式),否则下游解析器会失败。检查方法:
用 jq -R ‘fromjson’ /var/log/nginx/audit.json | head -5 验证前几行是否解析成功; 观察是否有 null 字段未被引号包裹(如 "http_x_forwarded_for":null 不合法,应为 "http_x_forwarded_for":""); 若字段为空,Nginx 默认输出空字符串,escape=json 会将其转为 "",符合 JSON 规范; 避免在 log_format 中使用未定义变量(如错写 $http_x_real_ip 而实际传的是 X-Forwarded-For),会导致字段缺失或空值。
不复杂但容易忽略。

评论(0)