postMessage是sandbox下唯一合规通信通道,启用sandbox后所有直接DOM访问失效,仅postMessage被浏览器明确支持;父页需校验event.origin且不写'*',子页须验证event.source并为敏感操作附加签名或token。

iframe 的 sandbox 机制和 postMessage 不是两套独立方案,而是一条必须串起来的安全链路:不启用 sandbox,跨域通信就失去隔离基础;只用 sandbox 不配 postMessage,子页就成哑巴;两者错配或漏校验,等于把门锁上又把钥匙焊在门把手上。
postMessage 是唯一能穿透 sandbox 的通信通道
sandbox 启用后,iframe.contentWindow.document 报 SecurityError,parent 为 null,document.domain 被忽略,连 eval() 和 Function 构造器都会被拦截。Chrome 117+ 还会静默丢弃 Date、RegExp、function 等非结构化数据——你传过去,对方收不到,也不报错。
- 必须用
postMessage,别试图绕过它去读写 DOM 或 localStorage - 父页发消息前,必须等
load事件触发,否则contentWindow是null - 子页加载失败(404/500)时
load仍会触发,建议配合error事件做兜底判断
sandbox="allow-scripts" 不等于“JS 全放开”
只加 allow-scripts 是最常见误判点。它允许 <script src> 和内联 <script> 执行,但所有 HTML 内联事件处理器全部失效:onclick、onload、javascript:void(0) 都静默不响应,控制台也不报错。
- 原因在于这些 handler 属于 HTML 解析阶段行为,受更底层策略约束
-
allow-scripts只解禁 JS 引擎,不开放 HTML 解析权限 - 如果需要表单提交,得显式加
allow-forms;需要弹窗,得加allow-popups
allow-same-origin 必须和 allow-scripts 组合且仅用于真正同源
allow-same-origin 单独写等于没写,浏览器直接忽略。它只有和 allow-scripts 同时存在,且 src 是协议、域名、端口三者完全一致的地址时才生效。
立即学习“前端免费学习笔记(深入)”;
- 给第三方页面(如
https://ads.example.com/widget.js)加该属性,既不生效,还暴露配置疏忽 - 生效后,子页可读写
localStorage、发起同源fetch,但window.parent仍是null,DOM 访问仍被隔离 - Chrome 126+ 已彻底移除
document.domain降域方案,别再试
origin 校验不能只 check 字符串包含
子页收消息时只写 event.origin.includes('example.com'),或父页发消息时 targetOrigin 写 '*',等于放弃安全防线。
- 子页应严格比对
event.origin === 'https://child.example.com'或event.origin === 'null'(动态写入 HTML 或about:blank场景) - 父页发消息前,应通过
event.source和event.ports判断是否来自预期窗口,避免响应伪造消息 - 敏感操作(如登录态同步、支付回调)必须附带签名或一次性 token,不能只靠 origin 校验
真正难的不是写对那一行 postMessage,而是整个链路里每处校验都得严丝合缝——少一个 load 监听、多一个 *、漏掉 event.source 判断,整条链就断在看不见的地方。



















