← 返回题目列表

window.postMessage 如何跨窗口通信?安全注意点有哪些?

中等 第 24 / 30 题 更新于 2026/07/29
浏览器postMessage跨窗口通信安全

简化版

postMessage 允许不同窗口、iframe、弹窗之间跨源发送消息。安全关键是发送时指定明确 targetOrigin,接收时校验 event.originevent.source 和消息结构,不能用 * 随便发敏感数据,也不能直接执行收到的内容。

详细版

常见场景:

  • 父页面和 iframe 通信。
  • 登录弹窗向主窗口返回授权结果。
  • 微前端子应用和主应用通信。
  • 第三方组件向业务页面发送事件。

安全要点:

  • 发送敏感消息时不要使用 * 作为 targetOrigin。
  • 接收消息必须校验来源域名。
  • 校验消息类型和字段,不信任任意对象。
  • 不要把 token、手机号等敏感数据发给不可信窗口。
  • 监听器不用时及时移除。

完整版教学

一、postMessage 解决同源策略下的受控通信

浏览器同源策略限制不同源页面互相读取 DOM 和 JS 对象,这是安全底线。但业务上确实需要跨窗口协作,例如父页面嵌入支付 iframe,登录弹窗把结果告诉主页面。postMessage 提供了一条受控消息通道。

它不是绕过同源策略,而是在明确发送和接收的前提下传递结构化数据。浏览器不会替你判断业务是否安全,校验责任在开发者。

主页面 A
  ├─ iframe B
  └─ popup C

A、B、C 不能随便读对方 DOM,但可以 postMessage 发送消息

二、targetOrigin 是第一道防线

发送消息时第二个参数是 targetOrigin,表示只有目标窗口当前 origin 匹配时才发送。敏感数据应该写明确域名,比如 https://pay.example.com,不要写 *

数字例子:一个登录弹窗原本在 https://auth.example.com,如果你向它发送 token 时使用 *,而弹窗被重定向到恶意页面,消息仍可能发出去。明确 targetOrigin 可以把这类风险挡住。

iframe.contentWindow.postMessage(
  { type: 'PAY_INIT', orderId: 'O1001' },
  'https://pay.example.com'
)

三、接收方必须校验 origin 和数据结构

任何页面都可能向当前窗口发送 message,所以接收方不能看到 message 事件就相信。必须检查 event.origin 是否在白名单内,再检查 event.data 的结构、类型和业务字段。

const allowOrigins = new Set(['https://auth.example.com'])

window.addEventListener('message', (event) => {
  if (!allowOrigins.has(event.origin)) return
  if (event.data?.type !== 'LOGIN_SUCCESS') return
  handleLogin(event.data.code)
})

如果消息里带 HTML、脚本、跳转地址,更要严格校验,避免 XSS 或开放跳转。

四、event.source 可以防止同源混淆

只校验 origin 有时还不够。同一个 origin 下可能有多个 iframe 或弹窗,业务上只信任其中一个。event.source 可以判断消息来自哪个窗口对象。

例如页面同时嵌入两个来自 https://widget.example.com 的 iframe,一个是客服,一个是支付。你期望支付 iframe 才能发 PAY_DONE,就应同时校验 event.source === payIframe.contentWindow

校验项解决问题
origin来源域名是否合法
source是否来自期望窗口
type消息类型是否允许
schema字段结构是否正确
business state当前流程是否允许接收

五、消息协议要有类型和版本

跨窗口通信最好设计成协议,而不是随便传对象。消息应包含 type、必要 payload、可选 requestId 和 version。这样可以做兼容、调试和错误处理。

比如微前端主应用和子应用通信,版本升级时旧子应用可能还在使用旧消息格式。带版本号就能让接收方选择兼容处理,而不是因为字段变化直接崩溃。

{
  type: "USER_CHANGED",
  version: 1,
  requestId: "r-8",
  payload: { userId: "u1" }
}

六、不要把 postMessage 当安全存储通道

消息可能被错误窗口接收,也可能被日志记录或插件观察。不要通过 postMessage 传长期 token、身份证、手机号等敏感数据。更安全的做法是传一次性 code 或短期票据,让可信服务端完成交换。

登录弹窗场景中,弹窗返回授权 code,主窗口再向自己后端换取 session,比直接返回 access token 更稳。这样即使消息被误处理,风险窗口也更小。

安全钩子:postMessage 能跨源发消息,但不能跨过你的安全审查;发前限定目标,收后验证来源和结构。

七、常见误区与追问

  • 误区:postMessage 可以安全地使用 * 非敏感广播可以考虑,敏感数据必须指定明确 targetOrigin。
  • 误区:只要收到 message 就说明来自目标 iframe。 任何窗口都可能发送,必须校验 origin、source 和消息结构。
  • 误区:origin 校验通过就能执行任意内容。 还要校验消息类型、字段和当前业务状态,不能直接执行字符串。
  • 追问:父子 iframe 怎么互发消息? 父页面用 iframe.contentWindow.postMessage,子页面用 parent.postMessage
  • 追问:登录弹窗返回什么更安全? 返回短期 code,由主页面后端换 session,避免直接传长期 token。
  • 追问:如何做协议兼容? 消息带 type、version、requestId,接收端按版本解析。

八、加强记忆

postMessage 用“指定目标、验证来源、校验结构、少传敏感”来记。它是跨窗口通信桥,不是信任豁免卡;发送端用明确 targetOrigin,接收端查 origin/source/type/schema,敏感链路传短期票据而不是长期秘密。