postMessage常见安全问题
字数 1537 2025-08-20 18:18:16

postMessage 安全实践指南

1. postMessage 基础概念

1.1 什么是 postMessage

postMessage 是一种跨源通信方法,它不受"同源策略"限制,允许不同源的网页之间进行安全通信。其他常见的跨域通信方法还包括 CORS 和 JSONP。

1.2 同源策略

同源策略是重要的安全策略,"同源"指的是协议、域名、端口都相同。非同源的两个资源间默认不能通信。

1.3 postMessage 工作原理

postMessage 跨源通信不受"同源策略"限制的前提:

  • 发送方需要有接收方 window 的引用
  • 发送方调用接收方 window 的 postMessage 方法发送消息
  • 接收方的消息监听器收到消息进行后续处理

2. postMessage 常见安全问题及修复方案

2.1 未指定接收方 origin

问题描述

  • 发送方直接向 top 发送消息,而不是其直接父级
  • 使用通配符 "*" 作为 targetOrigin,允许任何源接收消息
  • 消息内容包含敏感信息(URL、调用栈、cookie 等)

修复方案

  1. 在复杂的嵌套 iframe 结构中明确指定目标源
  2. 只向直接父窗口发送消息而不是直接向 top 发送消息
  3. 最小化通过 postMessage 传输的敏感信息
  4. 始终指定精确的目标 origin,而不是使用通配符 "*"

示例代码

// 安全的消息发送
window.postMessage("hello", "https://specific-domain.com");

// 消息接收
window.addEventListener("message", function(event) {
    console.log("Message received: ", event.data);
});

2.2 未验证消息来源

问题描述

  • 接收方未验证消息的 origin,直接处理接收到的数据
  • 可能导致任意域发送的消息被执行,造成 XSS 等安全问题

攻击示例

// 攻击者从任意域 iframe 发送恶意消息
frames[0].postMessage('append::<style onload="eval(alert(\'XSS via postMessage\'))">', "*");

// 不安全的接收处理
window.addEventListener('message', function(event) {
    parseMessage(event.data); // 直接处理未验证的消息
});

修复方案

  1. 始终验证 postMessage 的来源
  2. 对接收到的数据进行严格的验证和清理
  3. 避免直接执行或插入接收到的数据

安全代码示例

window.addEventListener('message', function(event) {
    // 验证来源
    if (event.origin !== "https://trusted-domain.com") return;
    
    // 安全处理消息
    // ...
});

2.3 消息传输数据结构

postMessage 传输的数据通常包含:

  • data: postMessage 的第一个参数,发送的信息内容
  • origin: 发送方的源(协议、域名、端口)
  • source: 发送方 window 的引用(可选内容)

3. origin 验证的常见错误及修复

3.1 正则表达式验证问题

错误示例

let re = /imgcache.test.com|user.openqa.test.com|www.dnspod.cn/
if(re.test(e.origin)){}

问题分析

  1. 缺少起止符(^ 和 $): 允许部分匹配
  2. 点号 (.) 没有转义: 在正则表达式中,点号匹配任意字符

绕过方式

  1. arbitrary.imgcache.test.com.subdomain.example.com - 利用缺少起止符
  2. imgcacheatest.com - 利用点号没转义
  3. imgcacheatestacom.example.com - 结合上述两个问题

修复方案

let re = /^(imgcache\.test\.com|user\.openqa\.test\.com|www\.dnspod\.cn)$/
if(re.test(e.origin)){}

3.2 endsWith 匹配问题

错误示例

if(e.origin.endsWith('test.com')){}

问题分析

  • 未考虑到域名边界
  • 任何以 'test.com' 结尾的字符串都会被匹配

绕过方式

  • arbitrarytest.com - 添加任意前缀的域名

修复方案

if(e.origin.endsWith('.test.com') || e.origin === 'test.com'){}

4. 最佳实践总结

  1. 精确指定目标 origin

    • 避免使用通配符 "*"
    • 明确指定接收消息的具体域名
  2. 严格验证消息来源

    • 使用完整的正则表达式验证,包括起止符和转义
    • 维护允许的源白名单
  3. 最小化敏感信息传输

    • 避免通过 postMessage 传输 cookie、token 等敏感信息
    • 限制消息内容范围
  4. 安全的消息处理

    • 对接收到的数据进行验证和清理
    • 避免直接执行或插入未经验证的数据
  5. 防御性编程

    • 考虑所有可能的边界情况
    • 实现多层防御机制

5. 示例代码模板

安全的消息发送

// 明确指定目标 origin
const targetWindow = document.getElementById('iframe').contentWindow;
const targetOrigin = 'https://trusted-domain.com';
targetWindow.postMessage({data: 'secure message'}, targetOrigin);

安全的消息接收

window.addEventListener('message', function(event) {
    // 验证来源
    const allowedOrigins = [
        'https://trusted-domain.com',
        'https://sub.trusted-domain.com'
    ];
    
    if (!allowedOrigins.includes(event.origin)) {
        return; // 拒绝非信任源的消息
    }
    
    // 验证消息内容
    if (typeof event.data !== 'object' || !event.data.hasOwnProperty('data')) {
        return; // 拒绝不符合格式的消息
    }
    
    // 安全处理消息
    processMessage(event.data.data);
});

function processMessage(data) {
    // 实现安全的消息处理逻辑
    // ...
}

通过遵循这些安全实践,可以充分利用 postMessage 的跨域通信能力,同时有效防范潜在的安全风险。

postMessage 安全实践指南 1. postMessage 基础概念 1.1 什么是 postMessage postMessage 是一种跨源通信方法,它不受"同源策略"限制,允许不同源的网页之间进行安全通信。其他常见的跨域通信方法还包括 CORS 和 JSONP。 1.2 同源策略 同源策略是重要的安全策略,"同源"指的是协议、域名、端口都相同。非同源的两个资源间默认不能通信。 1.3 postMessage 工作原理 postMessage 跨源通信不受"同源策略"限制的前提: 发送方需要有接收方 window 的引用 发送方调用接收方 window 的 postMessage 方法发送消息 接收方的消息监听器收到消息进行后续处理 2. postMessage 常见安全问题及修复方案 2.1 未指定接收方 origin 问题描述 : 发送方直接向 top 发送消息,而不是其直接父级 使用通配符 "* " 作为 targetOrigin,允许任何源接收消息 消息内容包含敏感信息(URL、调用栈、cookie 等) 修复方案 : 在复杂的嵌套 iframe 结构中明确指定目标源 只向直接父窗口发送消息而不是直接向 top 发送消息 最小化通过 postMessage 传输的敏感信息 始终指定精确的目标 origin,而不是使用通配符 "* " 示例代码 : 2.2 未验证消息来源 问题描述 : 接收方未验证消息的 origin,直接处理接收到的数据 可能导致任意域发送的消息被执行,造成 XSS 等安全问题 攻击示例 : 修复方案 : 始终验证 postMessage 的来源 对接收到的数据进行严格的验证和清理 避免直接执行或插入接收到的数据 安全代码示例 : 2.3 消息传输数据结构 postMessage 传输的数据通常包含: data : postMessage 的第一个参数,发送的信息内容 origin : 发送方的源(协议、域名、端口) source : 发送方 window 的引用(可选内容) 3. origin 验证的常见错误及修复 3.1 正则表达式验证问题 错误示例 : 问题分析 : 缺少起止符(^ 和 $): 允许部分匹配 点号 (.) 没有转义: 在正则表达式中,点号匹配任意字符 绕过方式 : arbitrary.imgcache.test.com.subdomain.example.com - 利用缺少起止符 imgcacheatest.com - 利用点号没转义 imgcacheatestacom.example.com - 结合上述两个问题 修复方案 : 3.2 endsWith 匹配问题 错误示例 : 问题分析 : 未考虑到域名边界 任何以 'test.com' 结尾的字符串都会被匹配 绕过方式 : arbitrarytest.com - 添加任意前缀的域名 修复方案 : 4. 最佳实践总结 精确指定目标 origin : 避免使用通配符 "* " 明确指定接收消息的具体域名 严格验证消息来源 : 使用完整的正则表达式验证,包括起止符和转义 维护允许的源白名单 最小化敏感信息传输 : 避免通过 postMessage 传输 cookie、token 等敏感信息 限制消息内容范围 安全的消息处理 : 对接收到的数据进行验证和清理 避免直接执行或插入未经验证的数据 防御性编程 : 考虑所有可能的边界情况 实现多层防御机制 5. 示例代码模板 安全的消息发送 安全的消息接收 通过遵循这些安全实践,可以充分利用 postMessage 的跨域通信能力,同时有效防范潜在的安全风险。