iframe沙箱是唯一安全可行的html/css/js隔离方案:必须用空srcdoc初始化,动态注入转义后的html,仅允许内联css和外链脚本(需cors),并通过postmessage捕获错误;allow-same-origin在srcdoc下有效但非真实同源,不兼容ie及旧版ios safari。

用 iframe 沙箱隔离执行 HTML/CSS/JS 是唯一安全可行的方案
浏览器禁止直接 eval() 或 new Function() 执行用户输入的完整 HTML(含 script 标签),因为会绕过 CSP、污染全局作用域、无法隔离 DOM。真正能跑起来且不炸掉页面的,只有 iframe + sandbox 属性这条路。
关键不是“怎么写”,而是“怎么隔离”:必须用空 srcdoc 初始化 iframe,再动态写入内容,否则跨域或缓存会导致脚本不执行或样式丢失。
-
iframe必须设置sandbox="allow-scripts allow-same-origin"(allow-same-origin仅在srcdoc场景下有效,且不等于真实同源) - 不能用
src="about:blank"后contentDocument.write()—— 现代 Chrome/Firefox 会拒绝执行其中的内联 script - 所有 CSS 必须内联(
<style></style>),外链<link>在 sandbox 下默认被禁,且无权限加载
srcdoc 动态注入时注意 HTML 转义和引号嵌套
用户写的代码要原样塞进 iframe[srcdoc],但 srcdoc 值是字符串,里面又含双引号、单引号、、<code>>,一不留神就语法断裂或 XSS。
- 对用户输入的 HTML 字符串,先用
document.createElement('div').textContent = input; return div.innerHTML做基础 HTML 实体转义(防<script></script>被解析为标签) - 拼接
srcdoc字符串时,整个值用双引号包裹,则内部所有双引号需转成";若用单引号包裹,则单引号转' - 避免手动拼接:推荐先构造完整 HTML 字符串,再用
encodeURIComponent()编码后赋给srcdoc(但注意srcdoc不支持 URL 编码,此法无效)—— 正确做法是只转义关键字符,不编码整串
JS 执行报错无法捕获?因为 iframe 的错误不在父页面上下文
你在主页面加 window.onerror 或 try/catch,完全收不到 iframe 里 JS 运行时报的 ReferenceError 或 SyntaxError。这是设计使然,也是沙箱的意义。
- 想获取错误信息,唯一办法是在注入的 HTML 中主动包裹一层
window.addEventListener('error', ...),并通过postMessage发回父页面 - 示例注入片段:
<script> window.addEventListener('error', e => { parent.postMessage({type: 'js-error', message: e.message, line: e.lineno}, '*'); }); </script> - 父页面监听:
window.addEventListener('message', e => { if (e.data.type === 'js-error') console.log(e.data) }) - 注意:
postMessage在 sandbox 下需要显式加allow-scripts allow-same-origin才能工作
移动端 Safari 和旧版 Edge 对 srcdoc 支持不一致
Android Chrome、Firefox、桌面 Safari 全支持 srcdoc;但 iOS Safari 10.3+ 才支持,iOS 10.2 及更早直接忽略该属性;IE 完全不支持(Edge Legacy 也无)。
- 检测方式:
const iframe = document.createElement('iframe'); 'srcdoc' in iframe - 降级方案只能是提示“不支持”或跳转到服务端渲染(纯前端无解)
- 不要尝试用
data:text/html,URI 替代 —— Safari 对 data URL 中 script 的执行限制更严,且容易触发 CORS 或 MIME 类型警告 - 如果必须兼容 IE,只能放弃纯前端方案,没有取巧办法
真正的难点从来不是“怎么让代码跑起来”,而是“怎么让它跑完还不影响主页面、不泄露数据、不出错也不让用户困惑”。srcdoc 是目前唯一平衡安全性与可行性的接口,但它的容错率极低——少一个引号、多一个未闭合标签、script 写在 head 里没 defer,都可能导致静默失败。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











