如何向启用sandbox属性的iframe正确发送postMessage?
解决iframe Sandbox模式下postMessage目标源不匹配的问题
问题现象
当注释掉iframe的sandbox属性时,所有功能运行正常;但取消注释后,Chrome控制台会抛出错误:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.bing.com') does not match the recipient window's origin ('null').
相关示例代码:
const iframeElement = document.createElement("iframe"); iframeElement.src = "https://www.bing.com" //iframeElement.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-scripts"); iframeElement.onload = (e) => { iframeElement.contentWindow.postMessage("foo", "https://www.bing.com"); }; const containerElement = document.getElementById("place-holder-for-iframe"); containerElement.appendChild(iframeElement);
原因分析
这是因为sandbox属性的默认行为会强制隔离iframe的源:当你启用sandbox但未指定allow-same-origin权限时,浏览器会将iframe的origin重置为null,完全切断它与自身原本源的关联。这时候你调用postMessage时指定的目标源https://www.bing.com,就和iframe实际的origin(null)不匹配,从而触发错误。
解决方案
你只需要在sandbox属性的权限列表中添加allow-same-origin,让iframe保留它原本的源身份即可:
修改后的代码:
const iframeElement = document.createElement("iframe"); iframeElement.src = "https://www.bing.com" // 添加allow-same-origin权限,让iframe保留自身源 iframeElement.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-scripts allow-same-origin"); iframeElement.onload = (e) => { iframeElement.contentWindow.postMessage("foo", "https://www.bing.com"); }; const containerElement = document.getElementById("place-holder-for-iframe"); containerElement.appendChild(iframeElement);
注意事项
添加allow-same-origin会让iframe恢复原本的源权限,这意味着它不再被完全隔离。如果你的父页面和iframe的源不同,需要确认这种设置是否符合你的安全需求——如果不需要iframe拥有同源权限,也可以考虑将postMessage的目标源改为"*"(不推荐,存在安全风险),但更安全的做法还是按需添加allow-same-origin并确保业务场景的安全性。
内容的提问来源于stack exchange,提问作者jojo




