postmessage 必须在 iframe 的 load 事件触发后调用,因插入 dom 后 contentwindow 仍为 null;需监听 load 事件并在回调中发送消息,且 targetorigin 严禁用 '*',子页接收时须严格校验 event.origin 和 data 结构。

postMessage 必须等 load 事件触发后才能调用
直接在 iframe 元素插入 DOM 后立刻调用 iframe.contentWindow.postMessage(),大概率静默失败——不是延迟不够,而是此时 contentWindow 仍为 null。DOM 节点已存在,但浏览器尚未完成 iframe 上下文初始化。
正确做法只有一条:监听 load 事件,且仅在此回调中访问 contentWindow:
const iframe = document.getElementById('sandbox-iframe');
iframe.addEventListener('load', () => {
// 此时 contentWindow 才真实可用
iframe.contentWindow.postMessage({ type: 'init' }, 'https://widget.example.com');
});
- 动态创建的
iframe,必须先appendChild()再绑定load,否则可能错过首次加载事件 -
src为空(如src=""或src="about:blank")或使用srcdoc,load仍会触发,但子页 JS 执行时机需额外确认 - 别用
setTimeout硬等,也别依赖iframe.onload = handler属性写法——它易被后续赋值覆盖 - 若子页加载失败(404/500),
load仍会触发,建议配合error事件做兜底判断
targetOrigin 绝不能写成 '*'
postMessage 的第二个参数不是“可选”或“省略即默认”,而是强制校验的安全边界。写成 '*' 等于主动放弃来源过滤,任何页面(包括被 XSS 注入的恶意 iframe、中间人劫持的伪造页面)都能接收该消息。
生产环境必须显式指定目标协议 + 域名 + 端口:
// ✅ 正确:只发给可信域名 iframe.contentWindow.postMessage(data, 'https://widget.example.com'); // ❌ 危险:测试偷懒,上线即暴露 iframe.contentWindow.postMessage(data, '*');
- 即使子页跑在
http://localhost:3000,也要写全,不能用'*' - 若子页有多个合法部署地址(如灰度
https://staging.widget.com和正式https://widget.example.com),发送前需逻辑判断并匹配对应 origin - 浏览器对
'*'不报错,但 CSP 的frame-src或connect-src可能拦截后续请求,导致通信链路断裂
子页收消息必须双重校验 event.origin 和 data 结构
只检查 event.data.type === 'pay_success' 或用 event.origin.includes('example.com'),形同虚设。攻击者可伪造任意字符串,绕过弱判断。
必须同时满足两个条件才处理消息:
-
event.origin严格等于预期域名(如'https://yourdomain.com'),不能用includes或正则模糊匹配 -
event.data是 plain object,且关键字段存在、类型正确(例如typeof event.data.order_id === 'string') - 敏感操作(如支付回调、登录态同步)应附带一次性 token 或签名,不能仅靠 origin 校验
- 若子页是
about:blank或srcdoc内联内容,event.origin会是'null',需显式比对而非忽略
sandbox 配置下 window.parent 始终为 null
启用 sandbox(哪怕只加 allow-scripts)后,子页的 window.parent 永远是 null,document.domain 在 Chrome 126+ 已彻底移除,allow-same-origin 对跨域 src 静默无效——这不是 bug,是浏览器强制隔离。
常见错误是给第三方支付页硬加 sandbox="allow-scripts allow-same-origin",以为能调 window.parent.paySuccess(),结果既没权限又暴露配置疏忽。
- 唯一合规通信路径只有
postMessage,父页和子页都必须走这条通道 - 子页发消息前,可通过
event.source判断是否来自预期父窗口,避免响应伪造消息 -
allow-same-origin仅当src真实满足协议+域名+端口三重一致时才生效;否则浏览器直接忽略该 token - 金融类场景必须禁用
allow-same-origin,所有状态存取由父页托管并通过postMessage传递
load 事件触发时机与 contentWindow 可用性之间的强耦合关系——它不是异步延迟问题,而是 DOM 初始化阶段的硬性约束;以及 event.origin === 'null' 这种特殊值,在 srcdoc 或空 src 场景下必须显式处理,不能跳过校验。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











