白名单机制通过仅允许特定html属性来防御onerror、javascript:等攻击,因其直接剥离未声明属性而非识别恶意;需配合协议限制、禁用style、慎用class/id,并与csp协同防护。

为什么只允许特定 HTML 属性能拦住 onerror、javascript: 这类攻击
因为浏览器在解析 HTML 时,会把 onerror、onclick、href="javascript:..."、src="data:text/html,..." 这些属性值当作可执行上下文处理。只要它们出现在最终渲染的 DOM 中,就可能触发任意脚本。白名单机制不靠“识别恶意”来过滤,而是直接拒绝所有未明确声明的属性——哪怕名字看起来无害(比如 is、nonce 在某些旧版浏览器中曾被利用),只要不在白名单里,一律剥离。
HTML.AllowedAttributes 配置时常见的漏配项
很多开发者只写 a[href],却忘了 img[src] 也得带 alt 才算完整;更隐蔽的是:iframe 标签即使被禁用,它的 sandbox 属性如果被单独放进白名单,反而会打开新的攻击面。实际配置中必须注意:
-
href和src必须配合协议白名单(如只允https://、/、#),否则href="javascript:alert(1)"会原样通过 -
style属性极危险,即使只放行color或text-align,攻击者仍可用expression()(IE)或url(javascript:...)绕过,建议默认禁用 -
class和id看似安全,但若后端逻辑依赖它们做 JS 选择器注入(如document.getElementById(userInput)),就可能引发 DOM XSS
innerHTML + 白名单净化 ≠ 安全闭环
很多人以为「先用 HTML Purifier 过滤,再塞进 innerHTML」就万事大吉,其实错在执行顺序和信任边界混淆。问题出在两处:
- HTML Purifier 输出的是字符串,一旦你把它赋给
el.innerHTML,浏览器会重新解析——如果净化器配置疏漏(比如漏了svg/onload),这段字符串仍会执行 - 更常见的是:用户输入先被净化,存入数据库;读取时又拼进模板(如
<div>${content}</div>),而模板引擎关闭了转义({{ content | safe }}),等于绕过净化层 - 真正安全的做法是:服务端净化后,前端用
textContent渲染纯文本;若需保留格式,改用createElement+setAttribute逐个构造,不走字符串插入路径
白名单不能替代 CSP,但 CSP 无法修复白名单漏配
CSP 的 script-src 'self' 可以阻止外链脚本,但它对内联事件处理器(onerror)、javascript: 伪协议、动态 eval 调用几乎无效。而白名单漏掉一个 onmouseover,CSP 就完全无能为力。反过来,如果白名单严格,但没配 CSP,攻击者仍可能通过 base 标签劫持所有相对 URL,或用 form[action] 提交敏感数据到外部域。二者必须共存,且白名单是第一道不可退让的防线。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











