在 log_format 中加入 $http_user_agent 是识别访问来源最基础关键的一步,需确保其被正确提取、结构化记录,并结合 map 分类与行为验证提升分析准确性。

直接在 log_format 中加入 $http_user_agent 是识别访问来源最基础也最关键的一步。它让每条日志都携带客户端声明的身份信息,后续所有爬虫分析、UA 指纹比对、行为关联都依赖这个字段是否被记录且格式稳定。
确保 UA 字段被正确提取和记录
Nginx 默认的 combined 日志格式已包含 $http_user_agent,但需确认两点:
- 你的
log_format定义中明确写了"$http_user_agent"(注意引号,避免字段截断) - 实际日志文件里该字段不为空——若前端有 CDN 或代理,部分请求可能缺失 UA(如健康检查探针),属正常;但真实用户或爬虫请求应有值
- 验证方式:执行
tail -5 /var/log/nginx/access.log,看每行末尾引号内是否有类似Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...的字符串
用结构化格式提升后续分析效率
不要只把 UA 当作一个字符串堆在日志末尾。建议在自定义格式中将其与关键字段对齐,方便用命令行快速切分:
- 推荐写法:
log_format audit '$remote_addr - [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'; - 这样 UA 始终是日志行的第 7 个字段(以空格为分隔符时),
awk '{print $7}'就能稳定提取 - 更稳妥的做法是用双引号分隔:
awk -F'"' '{print $8}' access.log(前提是 UA 是第 8 个引号包裹的字段,可通过head -1查看实际位置)
结合 UA 内容做初步分类与标记
光记录不够,要让日志本身带“语义”。可在 log_format 外配合 map 指令,把 UA 映射成可读标签:
- 例如定义:
map $http_user_agent $ua_type { default "unknown"; "~*baiduspider" "baidu-bot"; "~*Googlebot" "google-bot"; "~*curl|python-requests" "script-client"; } - 再把
$ua_type加入日志:"$http_user_agent" $ua_type - 这样查日志时,
grep "script-client" audit.log就能直接筛出脚本类请求,无需每次正则匹配
警惕 UA 伪造,必须叠加行为验证
UA 可被任意修改,单靠它判断是否恶意容易误伤或漏判。日志中真正有价值的,是 UA 和其他字段的组合表现:
- 同一 UA 在 1 分钟内发起 >30 次请求,且
$request_uri高度重复或规律性枚举(如/api/v1/user?id=1→/api/v1/user?id=2),大概率是扫描器 - UA 声称是 Chrome,但
$http_referer为空、$http_accept_language缺失、且$request_time普遍低于 20ms,不符合真实浏览器特征 - UA 字符串本身含 SQL 片段(如
user()、updatexml),说明攻击者把载荷注入了请求头——这种必须从日志中直接捕获,而非等 WAF 报警











