不能只靠accept或file.type判断html文件安全性,必须用filereader+domparser解析dom树,遍历script/iframe等标签及on事件属性,扫描高危函数和base64编码,超500kb跳过内容扫描,预览须用沙箱iframe且禁用allow-same-origin。

不能只靠 accept 或 file.type 判断 HTML 文件是否安全——浏览器返回的 MIME 类型可被伪造,扩展名可被重命名,静态字符串匹配会漏掉混淆写法(比如 onload=alert(1) 被写成 onload=alert(1))。真正的深度检测必须结合结构解析与行为观察。
用 FileReader + DOMParser 做结构化内容扫描
仅读取文本再正则匹配,容易被编码、注释、大小写绕过。应该把 HTML 字符串真正“解析”成 DOM 树,再遍历节点做判断:
-
FileReader.readAsText()读取后,用new DOMParser().parseFromString(html, 'text/html')构建文档对象 - 遍历所有
script、iframe、object、embed标签——这些是执行风险主通道,直接拒绝 - 检查所有元素的属性:用
element.hasAttributes()配合element.attributes循环,筛出含on开头的内联事件(如onclick、onerror) - 注意:DOMParser 对 malformed HTML 有容错性,但不会执行脚本,比
innerHTML更可控
提取并校验 script 标签内容(不执行)
有些恶意 HTML 把逻辑藏在 <script></script> 块里,或通过 eval、setTimeout、atob 动态还原。前端虽不能执行,但可做轻量级特征提取:
- 对每个
script节点的textContent,用正则扫描高危模式:/\b(eval|setTimeout|setInterval|fetch|XMLHttpRequest|atob|btoa)\b/i - 检查是否含 base64 编码片段(如
/data:text\/html;base64,[A-Za-z0-9+/]*={0,2}/) - 避免全局
replace或matchAll大文本——若文件 >500KB,跳过内容扫描,仅做结构层拦截
沙箱 iframe 预览前必须切断执行链
如果业务要求“上传前预览 HTML 行为”,绝不能直接 innerHTML = html ——这等于执行了所有内联脚本。正确做法是:
- 将校验通过的内容转为
Blob:new Blob([html], {type: 'text/html'}) - 生成沙箱 URL:
URL.createObjectURL(blob) - 加载到
<iframe sandbox="allow-scripts" src="..."></iframe>——注意:去掉allow-same-origin,否则可绕过同源策略读取父页面数据 - 预览 iframe 加载完成后,可通过
iframe.contentWindow?.document检查其实际渲染结构,但无法访问其 JS 执行上下文
为什么哈希校验不能代替内容检测
crypto.subtle.digest('SHA-256', await file.arrayBuffer()) 算出的哈希值,只反映字节一致性,不反映语义安全性。两个哈希完全相同的 HTML 文件,可能一个合法,另一个只是把 <script></script> 标签用注释包裹后又解包执行——哈希不变,风险已存在。所以哈希只适合去重或传输校验,不能跳过 DOM 解析步骤。
最容易被忽略的是:DOMParser 解析后,document.querySelector('script') 可能返回 null(因为 script 被注释或动态插入),但真实浏览器环境仍会执行。因此,任何“看起来没 script”的 HTML,只要含可疑属性或编码 payload,都应拦截。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











