如何防止被打开窗口篡改父窗口的关闭方法,同时确保父窗口可可靠关闭子窗口?
如何防止被打开窗口篡改父窗口的关闭方法,同时确保父窗口可可靠关闭子窗口?
这个问题确实挺闹心的——子窗口居然能篡改父窗口用来控制它的关闭方法,想用noopener隔离又会切断自己对子窗口的控制权。我来给你分享几个靠谱的解决思路:
方法一:用postMessage跨窗口通信(推荐,跨域也能用)
既然直接操作子窗口的原生方法会触发浏览器安全限制,那我们换个思路:让子窗口自己执行关闭操作,父窗口只需要发个“指令”就行,完全绕开被篡改的close方法。
父窗口(test1.html)代码
// 打开子窗口并保存引用 const janela = window.open("http://localhost/test2.html","_blank","width=1000,height=400,left=600,top=0"); // 封装关闭子窗口的函数 function closeChildWindow() { // 先判断子窗口是否还存在 if (janela && !janela.closed) { // 发送关闭指令,生产环境一定要把*改成子窗口的具体域名,比如"http://localhost" janela.postMessage({ type: "CLOSE_ME" }, "*"); } }
子窗口(test2.html)代码
// 监听来自父窗口的消息 window.addEventListener("message", (event) => { // 重点!生产环境必须验证event.origin,只处理可信域名的消息,防止恶意攻击 if (event.origin === "http://localhost" && event.data.type === "CLOSE_ME") { window.close(); // 自己执行关闭操作 } }); // 你原来的篡改代码可以保留,不会影响父窗口发指令关闭 opener.window.janela.close = null;
这种方式完全符合浏览器安全策略,不管子窗口怎么折腾父窗口的变量,都能稳稳关掉它。
方法二:同域名场景下用noopener+命名窗口
如果你的父窗口和子窗口是同域名,而且子窗口不会跳转到其他网站,那可以用noopener隔离子窗口,同时给子窗口指定唯一名称,之后通过同名引用关闭它。
父窗口(test1.html)代码
// 给子窗口起个唯一的名字 const childWindowName = "myTestWindow"; // 用noopener打开,彻底阻止子窗口篡改父窗口 window.open("http://localhost/test2.html", childWindowName, "width=1000,height=400,left=600,top=0,noopener"); // 关闭子窗口的函数 function closeChildWindow() { // 通过空URL+窗口名称获取子窗口引用 const childWindow = window.open("", childWindowName); if (childWindow) { childWindow.close(); } }
这个方法的原理是同域名下,同名窗口可以通过window.open('', 名称)重新获取引用,就算之前的引用被篡改也没关系。但如果子窗口跳去了其他域名,这个方法就失效了,所以只适合同域名且固定页面的场景。
为什么你之前的尝试报错?
你之前把父窗口的close方法赋值给子窗口的myClose,浏览器会因为同源策略拦截这种操作——原生的window方法属于浏览器内部对象,跨域窗口之间不能直接共享这类方法,所以才会弹出“违反安全策略”的错误。而postMessage是浏览器专门设计的跨窗口通信机制,是被允许的合法操作。
备注:内容来源于stack exchange,提问作者Samul
相关产品推荐
相关产品推荐

