HTML是XSS等漏洞主战场,关键在管控用户输入的进出与信任;高危输出点包括innerHTML赋值、未转义模板渲染、URL参数反射;需上下文敏感转义而非简单标签过滤,并验证响应头与富文本净化措施。

HTML代码本身不执行逻辑,但它是XSS、注入、信息泄露等漏洞的主战场。检测和处理的关键不是“扫出多少行代码有问题”,而是盯住用户输入如何进、如何出、是否被信任。
怎么快速定位XSS高危输出点
所有把用户可控数据直接拼进HTML的地方,都是XSS入口。重点查三类位置:
-
innerHTML赋值(尤其是用document.getElementById().innerHTML = userInput这种) - 模板字符串或
v-html/{{ }}渲染未转义内容(Vue/React中误用v-html或 dangerouslySetInnerHTML) - URL参数反射到页面:比如
?name=Tom导致<h2>Hello Tom</h2>且没做textContent或 HTML实体编码
实操建议:打开浏览器开发者工具 → Elements 面板 → 搜索 <script>、onerror=、javascript:;再用 Burp Suite 或手动改 URL 参数插入 <img src=x onerror=alert(1)>,看是否触发。
为什么只过滤 <script></script> 标签远远不够
攻击者根本不会老老实实写 <script>。常见绕过方式包括:
立即学习“前端免费学习笔记(深入)”;
- 事件处理器:
<svg/onload=alert(1)>、<body onload=alert(1)> - 伪协议:
<a href="javascript:alert(1)">click</a>、<img src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="> - 大小写混淆:
<ScRiPt>alert(1)</sCrIpT>、双重 URL 编码:%253cscript%253e
所以不能靠黑名单删关键词,而要在输出时做上下文敏感转义:插在 HTML 文本中用 textContent 或 htmlspecialchars();插在属性里用引号包裹 + 属性值 HTML 编码;插在 JS 字符串里用 JSON.stringify() 包一层。
如何验证响应头是否真起作用
光配了 Content-Security-Policy 或 X-Content-Type-Options 不代表生效。必须验证:
- 用
curl -I https://yoursite.com看响应头里有没有Content-Security-Policy:字段,且值不是空或明显宽松(如含unsafe-inline) - 在浏览器 DevTools → Network → 刷一个页面 → 点开任意请求 → Headers → Response Headers,逐条确认
Strict-Transport-Security、X-Frame-Options是否存在 - 用在线工具如 securityheaders.com 扫描,它会标出缺失项和配置风险(比如
report-uri已废弃,应改用report-to)
特别注意:CSP 的 default-src 'self' 是好起点,但如果页面用了内联样式或脚本,又没加 nonce 或 hash,就会被拦截——这时候不能直接加 'unsafe-inline',得重构代码。
富文本编辑器里的漏洞最难防,因为“合法”和“恶意”边界模糊
像 TinyMCE、Quill、CKEditor 这类组件,允许用户输入 HTML,但默认过滤规则往往有盲区。检测时要重点关注:
- 是否允许
<svg>、<math>、<style>标签(它们可嵌入 JS) - 是否对
on*事件属性做过滤(有些只过滤onclick,漏掉onanimationstart) - 是否校验
src属性协议(允许data:或javascript:就危险)
修复建议:不用“自己写过滤器”,而用成熟白名单库,比如 DOMPurify(前端)或 jsoup(Java 后端),并开启 SAFE_FOR_TEMPLATES 或 FORBID_TAGS 选项。后端存储前必须二次净化,不能只信前端传来的“已清理”数据。
最常被忽略的一点:HTML 注释、meta 标签、data- 属性、隐藏的 div 里可能埋着测试账号、API密钥、未关闭的 debug 模式开关——这些不触发 XSS,但直接暴露攻击面。每次上线前,Ctrl+U 看源码,别只盯着功能区域。



















