白名单校验必须贯穿解析→校验→重建全过程,动态模块、script src、import()路径、href及DOMPurify均需严格校验协议、域名、端口与内容,禁用危险协议与未授权值,多层嵌套须重复净化。

直接说结论:白名单校验不是加个配置就完事,它必须贯穿「解析→校验→重建」全过程,漏掉任一环节都等于开门揖盗。
data-module 动态加载必须走模块白名单
HTML里写 data-module="comments" 看似无害,但只要没做白名单校验,攻击者就能塞进 data-module="<script>alert(1)</script>" 或绕过解析直接触发执行。
- 模块加载器启动前,必须比对
data-module值是否在预设数组里,比如['comments', 'share', 'rating'] - 未注册的值一律跳过,不报错、不 fallback、不尝试加载——静默丢弃是最安全的响应
- 白名单不能写在 JS 里硬编码,建议从后端注入到全局变量(如
window.ALLOWED_MODULES),避免被篡改 - 注意大小写和空格:
"COMMENTS"和"comments "都应视为非法
script src 的协议与域名必须精确到 host + port
<script src="//cdn.example.com/bundle.js"></script> 这种协议相对 URL 是典型隐患,中间人可劫持为 http:// 并注入恶意脚本。
- 校验逻辑必须拒绝所有不含协议的 src(即以
//开头)、javascript:、data:、blob:等伪协议 - 白名单条目应是完整 host + port,例如
"cdn.jsdelivr.net:443",而非"jsdelivr.net"—— 后者无法防子域名污染 - 动态 import() 调用同样适用该规则:
import('/js/feature.js')中的路径需经同一套校验函数处理 - 本地开发时允许
localhost:3000,但上线环境必须移除,防止调试残留
href 属性必须限制协议且拒绝危险字符
用户提交的富文本里,一个看似正常的链接 @#@#@#@#@#@#@#@#@#@0 就能直接触发 XSS。
- 正则校验推荐用
^(https?|ftp)://[^\s/$.?#].[^\s]*$,它强制协议存在、禁止空主机、排除空白和控制字符 - 绝对不允许
href="javascript:"这类 HTML 实体编码绕过 - 对相对路径(如
/admin/delete)不做拦截,但需确保后端路由本身有权限控制,前端不承担鉴权责任 - 锚点链接(
#section1)可放行,但要剥离末尾的javascript:混淆,比如#section1%0Ajavascript:alert(1)
DOMPurify 的 sanitize 不能当黑盒用
很多人调一句 DOMPurify.sanitize(dirtyHtml) 就以为万事大吉,但默认配置下仍可能放过危险内容。
- 必须显式传入配置对象,至少启用
{ALLOWED_TAGS: [...], ALLOWED_ATTR: [...], FORBID_TAGS: ['script', 'iframe'], FORBID_ATTR: ['onerror', 'onclick']} -
USE_PROFILES: {html: true}可快速启用 HTML 安全子集,但它不包含svg或math,若业务需要得手动补全 - 对
style属性要额外设ALLOWED_STYLES,否则默认放行所有 CSS,可能被用于 CSS 注入(如background:url(javascript:...)) - 服务端使用时(Node.js),务必用
DOMPurify.sanitize(html, {WHOLE_DOCUMENT: false}),否则会把也当内容处理,导致渲染异常
最容易被忽略的是「多层嵌套校验」:前端 DOMPurify 净化后,若内容又拼进 innerHTML、再被第三方组件二次解析,就可能绕过第一道检查。真正稳的做法,是入库前净化 + 渲染前再过一次轻量校验,而不是依赖某一层兜底。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











