用 iframe + sandbox 可开箱即用,但需手动解决 dom 注入、脚本隔离和样式污染;核心是 sandbox="allow-scripts",禁用 allow-same-origin,动态注入须用 contentdocument.write(),css/js 需作用域隔离。

直接用 iframe + sandbox 就能跑起来,不需要框架、不依赖后端、本地文件也能开箱即用——但前提是必须手动处理 DOM 注入、脚本隔离和样式污染这三道坎。
用 iframe sandbox="allow-scripts" 安全执行代码
浏览器原生支持的 iframe 沙箱机制是核心。它默认禁用脚本、表单提交、插件、弹窗等能力,只保留渲染和有限 JS 执行权。关键不是加不加 sandbox,而是加哪些权限:
-
sandbox="allow-scripts"是底线,没有它 JS 一行都不跑 - 绝对不要加
allow-same-origin,否则用户代码可读取主页面 Cookie 或 localStorage - 如果示例里用了
fetch或XMLHttpRequest,得额外加allow-net(仅限可信环境,如本地 file:// 协议下调试) - Chrome 对
file://协议下的fetch有严格限制,开发时务必用npx serve或 VS Code Live Server 启服务
把编辑器内容动态注入 iframe 的正确姿势
不能用 srcdoc 一劳永逸——它不支持跨域资源加载(比如 CDN 引入 Vue),也不支持相对路径引用 CSS/JS 文件。更可靠的做法是通过 document.write() 写入完整文档结构:
- 先用
iframe.contentDocument.open()清空并打开写入流 - 再用
write()拼接完整的...字符串,确保里有<meta charset="utf-8">和<meta name="viewport"> - JS 代码必须包裹在
<script></script>标签内,且避免使用document.write()自身——它会清空当前文档,造成死循环 - 若需调试,可在注入前给 JS 加一层包装:用
try...catch捕获错误,并把console.error重定向到主页面的<div class="output"> <h3>避免 CSS 和 JS 全局污染的硬约束</h3> <p>用户写的 <code>body { margin: 0 }或Array.prototype.push = () => {}会直接影响主页面。这不是 bug,是设计缺陷:- CSS 隔离只能靠强制作用域:给所有用户样式加前缀,或用
iframe自带的样式隔离(推荐) - JS 全局污染无法完全杜绝,但可通过创建独立
Function实例来限制作用域:new Function('return (function(){' + userCode + '})();')(),比eval更可控 - 禁止用户代码访问
window.parent、window.top、document.cookie等敏感属性,可在沙箱 iframe 中提前覆盖这些属性为undefined - 别信“只允许 HTML/CSS/JS 输入”这种说法——只要允许执行 JS,就等于给了用户一个任意代码执行入口
真正难的不是让代码跑起来,而是让跑起来的代码既不崩主站、也不偷数据、还不被 XSS 利用。每加一行注入逻辑,都得同步补上对应的防御层;每次放宽一个 sandbox 权限,都要问一句:这个功能真的非开不可吗?
- CSS 隔离只能靠强制作用域:给所有用户样式加前缀,或用











