应重点分析access.log中被拦截的高频异常请求,包括含未编码标签的400请求、短时间多次含xss特征的get/post请求、超大content-length导致500的请求及非常规user-agent等,通过awk+grep快速筛查并关联时间窗口识别试探链。

直接看 access.log 里带 /run-html 的 400/500 请求
HTML 在线运行服务(比如用户提交 <script>alert(1)</script> 让后端渲染)一旦被滥用,攻击者通常会连续试探多种 payload。这些请求不会进业务逻辑层——网关或中间件已拦截,但它们全都会记入 Nginx 或 OpenResty 的 access.log。重点不是查“成功执行”的请求,而是查被拒绝却高频出现的异常路径。
典型线索包括:
/run-html?html=<script> 这类 URI 中含未编码标签的 400 请求</script>- 同一 IP 在 1 分钟内发起 >5 次含
onerror=、javascript:的 GET 请求 - POST 到
/run-html且Content-Length> 10KB 但响应状态为 500(可能触发 Lua body 扫描超时或正则回溯) - User-Agent 是
curl/7.68.0或空值,且无 Referer
用 awk + grep 快速提取可疑 IP 和 payload 片段
别打开日志文件手动翻。生产环境日志量大,直接命令行筛:
awk '$9 ~ /^(400|403|500)$/ && $7 ~ /\/run-html/' /var/log/nginx/access.log | \
grep -E '(<script awk sort uniq head><p>这行命令做了三件事:<ul><li>先过滤出状态码为 <code>400/<code>403/<code>500 且路径含 <code>/run-html 的行<li>再匹配常见 XSS 片段(注意:正则写法要避开过度匹配,比如 <code>alert\( 而不是 <code>alert)<li>最后按 IP+路径聚合计数,取 Top 20<p>如果看到某 IP 高频触发 <code>?html=%3Cimg%20onerror%3D...,基本可判定是自动化扫描器。<H3>关联时间窗口,识别多阶段试探行为<p>单次 400 不代表攻击,但连续行为才有意义。比如一个 IP 先发 <code>/run-html?html=<script>(被拒),2 秒后发 <code>/run-html?html=<img+src=x+onerror=alert(1)>(又被拒),再过 3 秒 POST 含 base64 编码 payload 的 JSON——这就是典型试探链。<p>用以下命令提取某 IP 在 60 秒内的全部相关请求:<pre class="brush:php;toolbar:false;">awk -v ip="192.168.1.100" '$1 == ip && $7 ~ /\/run-html/' /var/log/nginx/access.log | \
awk '{gsub(/\[|\]/,"",$4); print $4,$9,$7}' | \
sort -k1,1</script>
关键点:
-
$4是原始时间字段(如[12/Jun/2026:14:22:01),需先清理方括号才能排序 - 排序后肉眼扫时间差,>5 秒间隔一般不算连贯试探;≤3 秒且 payload 复杂度递增,大概率是工具自动打点
- 不要只看状态码——有些 payload 会故意触发 500(比如超长字符串导致 Lua 字符串匹配栈溢出),这类更危险
注意日志里隐藏的绕过尝试
攻击者知道你在查 <script></script>,所以会用变形:
- URL 编码:
%3Cscript%3E或双写:<script> - 大小写混用:
<script></script>(Nginx 默认正则不区分大小写,但若你用了~而非~*就可能漏掉) - 利用注释绕过:
<!-- --><script></script>或<svg onload="..."></svg>(svg不在基础黑名单里)
所以日志审计不能只依赖固定关键词。真正难搞的是那些没触发拦截、却悄悄进了后端的请求——它们可能状态码是 200,但 response body 里有 eval( 或 document.write。这时候必须结合应用层日志(如 Spring Boot 的 logback 输出)交叉比对,而不仅是 Nginx access log。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











