有没有办法阻止 iframe 沙箱发送 postMessages?

Is there a way to prevent an iframe sandbox from sending postMessages?

假设我有一个带有属性 sandbox="allow-scripts" 的 iframe。

我可能会或可能不会控制加载该 iframe 的页面。 除了覆盖父 postMessage 函数之外,是否有任何可能如何防止 iframe 发送 postMessages - 如果父不是我的域,我可能无法做到这一点。

一位同事想出了一个主意。可以总结为:将父域作为域的一部分,以便可以覆盖其 postMessage 方法。

如果无法控制包含 iframe 的顶部 window,为什么不将原始 iframe 放在另一个 iframe 中。额外的框架层可以充当防火墙。通过覆盖该中间防火墙-iframe 的 postMessage-Method,可以确保原始 iframe 可以随心所欲地发布消息,但防火墙-iframe 仅转发希望可发布的传入消息。

当然,这对于 postMessage 调用的目标域必须是什么有一些限制。

您应该只检查 MessageEvent 的只读 source 属性。

<iframe src="evil.html" class="ignore-messages"></iframe>
<iframe src="safe.html"></iframe>
window.addEventListener('message', function(e)
{
    // Blacklist messages if e.source matches iframe.ignore-messages
    if(Array.from(document.querySelector('iframe.ignore-messages'))
            .map(f => f.contentWindow)
            .indexOf(e.source) !== -1
      ) return;
    
    // handle message from safe.html
    // this message cannot come from evil.html,
    // since that iframe has the class "ignore-messages"
};

实现此目的的其他方法是通过白名单,例如:

// allow only from parent
if(e.source !== parent) return;
// allow only from a given set of iframes
if(Array.from(document.querySelectorAll('iframe.accept-messages')).map(f => f.contentWindow).indexOf(e.source) === -1) return;

白名单相对于黑名单的优势在于,发送消息的 iframe 可能不再在 DOM-树中,或者 classList 可能已更改等。哪个更常见使用 javascript 生成的动态 HTML 时。因此,使用白名单是一种万无一失的方法。