iframe sandbox:它收窄能力,不是加固
sandbox 属性默认剥夺一切能力,靠 allow-* 逐项放回。弄反方向是常见错误:加上 sandbox 之后脚本全不能跑了,因为那是默认值。
<iframe sandbox> 的语义容易记反:空值是最严格的,它剥夺脚本、表单、同源、弹窗、下载等一切能力,然后由 allow-* 一项项放回来。
<iframe sandbox="" src="/embed/comment.html"></iframe>
这个 iframe 里 JS 不执行、表单不能提交、被当成独立源。适合纯展示内容。
逐项放权
| 值 | 放回什么 | 风险 |
|---|---|---|
allow-scripts |
执行 JS | 配合下一项才危险 |
allow-same-origin |
保留原源,可读 cookie | 与 scripts 同用等于没沙箱 |
allow-forms |
提交表单 | 中 |
allow-popups |
开新窗口 | 中,可被钓鱼利用 |
allow-top-navigation |
导航顶层页面 | 高,可劫持整页 |
最危险的一对
sandbox="allow-scripts allow-same-origin" 在与被嵌入页同源时基本等于没有 sandbox:脚本跑起来,且能访问父页面的 DOM —— 它可以直接删掉 sandbox 属性再重载自己。
正确做法是把嵌入内容放到不同源(独立的子域),此时 allow-same-origin 指的是「子域自己的源」,跨源隔离仍然成立。
不要拿它当 CSP 用
sandbox 管的是这个 iframe 能做什么,CSP 管的是这个文档能加载什么。两者互补,不能互替:
- 要阻止内联脚本 → CSP
script-src - 要阻止 iframe 导航父页 → sandbox
- 要阻止 iframe 发请求 → 只能靠 iframe 内部自己的 CSP
实践建议
| 嵌入对象 | 建议配置 |
|---|---|
| 第三方评论组件 | allow-scripts allow-same-origin allow-popups |
| 视频播放器 | allow-scripts allow-same-origin allow-presentation |
| 纯展示文档 | ``(空) |
| 用户提交的 HTML | 不放 iframe,改为 sanitize + 独立源 |
最后一条是安全底线:用户提交的 HTML 永远不要用 iframe 加载。同源下的 sandbox 有绕过史,独立源才可靠。
sandbox 是白名单不是黑名单。写下
allow-*之前先问:这个能力被拿走会怎样?

评论
…