sandbox属性默认完全禁用脚本执行,必须显式添加allow-scripts才允许外链脚本运行,但内联脚本、事件处理器、eval等仍被静默丢弃;allow-scripts与allow-same-origin同用存在严重风险,需配合referrerpolicy、srcdoc、CSP等纵深防御措施。

sandbox 属性加了就脚本全关,不是“限制”而是“锁死”——想让 JS 跑起来,必须显式写 sandbox="allow-scripts",否则 alert(1)、fetch()、onclick 全部静默失效,控制台不报错、Network 不发请求、页面白屏或功能瘫痪。
为什么写了 sandbox 却连 alert(1) 都不弹
浏览器把 <iframe sandbox></iframe> 当作“零权限容器”,直接跳过所有脚本解析阶段:<script>alert(1)</script>、onclick="alert(1)"、javascript:void(0)、eval()、setTimeout("alert(1)") 全被丢弃。这不是 JS 报错,是根本没进执行队列。
-
sandbox=""、sandbox=" "、sandbox(无值)三者等效,全部锁死 - 动态设置
iframe.sandbox = "allow-scripts"无效——DOM 插入后改属性不生效 - 验证是否生效:控制台执行
document.querySelector('iframe').sandbox,返回空DOMTokenList []表示没开任何权限
allow-scripts 能跑什么、不能跑什么
allow-scripts 只放行通过 <script src="..."></script> 加载的外部脚本,且该资源需满足 CORS 或同源;它不恢复任何内联执行能力。
- ✅ 可运行:
<script src="https://trusted.example/widget.js"></script>(服务端需返回Access-Control-Allow-Origin) - ❌ 不可运行:
<script>console.log('nope')</script>(内联 script 标签静默忽略) - ❌ 不可运行:
<button onclick="fetch('/api')">click</button>(内联事件处理器完全失效) - ❌ 不可运行:
data:text/javascript,alert(1)(data:协议默认被拦,加allow-same-origin极危险) - ⚠️ 注意:
allow-scripts不递归授权——外链脚本里再document.write("<script></script>")仍被禁止
常见误配组合与真实风险
很多人堆砌 token 图省事,结果等于撤掉沙箱。最典型的是把 allow-scripts 和 allow-same-origin 同时加在第三方 iframe 上。
-
sandbox="allow-scripts allow-same-origin"用于加载https://third-party.com/widget.html→ 因不同源,allow-same-origin被浏览器直接忽略,但暴露了配置疏漏 -
allow-same-origin单独存在无意义,只在src确实与父页协议+域名+端口全一致时才生效;一旦和allow-scripts同时启用且同源,iframe 就能读写自身localStorage、发起同源fetch(),但仍不能访问window.parent - 生产环境嵌第三方内容时,绝对不要加
allow-same-origin;仅限内部可信同源页面(如https://yourdomain.com/admin/)
必须配合的纵深防御措施
sandbox 单独使用远远不够,需叠加以下防护:
立即学习“前端免费学习笔记(深入)”;
-
referrerpolicy="no-referrer":防止 iframe 内请求泄露来源 URL -
loading="lazy":延迟加载非首屏 iframe,减少初始攻击面 -
srcdoc替代src:对简单静态内容(如说明卡片),直接内联 HTML,避免外部资源加载风险 - 服务端设置
X-Frame-Options: DENY或Content-Security-Policy: frame-ancestors 'none':从源头禁止被他人嵌入,与sandbox形成双向防护
真正可控的安全隔离,从来不是靠一个属性搞定的——sandbox 是起点,不是终点;每个加上的 token 都意味着额外攻击面,而最容易被忽略的,是那些静默失效的行为:比如 console.log 不输出、addEventListener 绑定无声无息、表单点击毫无反应。你得先意识到它没动,才能去查它为什么不动。



















