用 postMessage 检查 window.parent 的来源有什么意义吗?

Fra*_*y I 5 javascript iframe postmessage cross-domain same-origin-policy

我有一个脚本,旨在由创建 iframe(在我们的源上)的第三方站点包含。像这样的东西:

// this script exists on the *host site*
const iframe = document.createElement("iframe");
iframe.src = "https://us.com/iframe";
parent.appendChild(iframe);
Run Code Online (Sandbox Code Playgroud)

该脚本公开了一个 API,该 API 通过 与 iframe 进行内部通信postMessage,例如:

// This script exists on the *host site*
function getSomeProperty()
{
    return new Promise(function (resolve, reject)
    {
        theIFrame.postMessage("getSomeProperty", "us.com")
        window.addEventListener("message", function (event)
        {
            // ... get the response, making sure its from us.com, etc.
            // This is just pseudo code, we don't create a new listener
            // on every call in our real code.
            resolve(answer);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

这一切都很好,我的问题是关于 iframe 相应的“消息”侦听器。具体而言,我想只有尊重从创建窗口/产地请求。换句话说,如果某个单独来源(例如广告)上的并行 iframepostMessage向我们构造了 a ,我们当然希望忽略这一点。我的问题是它是否足够简单地检查是否发送windowwindow.parent

const parent = window.parent;

// This event handler is in the *embedded iframe*
window.addEventListener("message", function (event)
{
    // This is being sent from a window other than 
    // the one that created us, bail!
    if (event.window !== parent)
         return;

    // it is safe to respond...
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这不是一个充分检查的唯一方法是 window.parent 是否有可能改变原点,同时让我们在身边。我可以想象一个 iframe 可以从一个主机上删除并将 appendChild'ed 到另一个主机上的场景,但我相信这只有在 DOM 操纵器位于同一来源(因此可以访问所述 DOM)并将我们置于另一个同样起源的窗口。

目前,我们采用了一种额外的偏执防御,通过查询字符串将原始来源传递给 iframe,如下所示:

const iframe = document.createElement("iframe");
iframe.src = `https://us.com/iframe?location=${window.location.href}`;
Run Code Online (Sandbox Code Playgroud)

从而允许我们检查那个window === window.parentAND origin === originalOrigin。然而,我们真的很想摆脱这种模式,因为它必然会破坏不同站点之间的缓存(因为每个站点由于不同的查询字符串而生成不同的 src URL)。那么,我们转向单独检查window === window.parent是否安全?

Nic*_*ley 0

使用postMessageAPI 时,确保消息来自指定位置的唯一真正安全的方法是使用严格的targetOrigin. 这样您就可以确保消息来自您控制的窗口。

您说得对,这种情况会阻止来自创建消息的窗口之外的传入消息。但是,仍然可以在任何 originsrc="https://us.com/iframe";上创建iFrame 。如果它是在恶意页面上创建的怎么办?这仍然满足这样的条件: 。window.parent === parenttrue