window.opener是BOM中指向父窗口的对象,同源下可操控父页面DOM、跳转、调用函数等,但存在钓鱼与XSS风险;应通过rel="noopener"或window.open()的noopener特性禁用opener引用以阻断攻击。

在JavaScript中,window.opener 是BOM(Browser Object Model)中一个关键但常被忽视的属性,它指向通过 window.open() 打开当前窗口的那个父窗口对象。合理使用它可以实现父子窗口通信,但滥用或忽略安全防护(如未设置 noopener)则可能引发严重的钓鱼与XSS风险。
opener 属性如何反向控制父窗口
当子窗口由 window.open() 打开且未禁用 opener 时,子窗口可通过 window.opener 直接访问并操作父窗口的 DOM、执行脚本、修改 location 等——前提是两个页面同源(协议、域名、端口一致)。跨域情况下,opener 存在但大部分属性/方法会被浏览器限制访问(抛出 SecurityError)。
常见可控操作包括:
-
跳转父页面:
window.opener.location.href = "https://example.com"(同源下生效) -
调用父窗口函数:若父页定义了
window.refreshList = () => { ... },子页可执行window.opener.refreshList() -
读写父页全局变量(同源):
window.opener.userData = { id: 123 }; -
关闭父窗口(需用户授权):
window.opener.close()(现代浏览器通常拦截)
为什么 opener 会带来钓鱼安全隐患
核心风险在于:如果一个不可信的第三方网站(比如恶意广告页)通过 window.open() 被打开,而原页面未做安全隔离,该子页就能通过 window.opener 操控父页——例如将父页重定向到钓鱼登录页,诱导用户输入账号密码。
立即学习“Java免费学习笔记(深入)”;
典型攻击链:
- 用户点击某“抽奖链接”,触发
window.open("https://malicious.site/phish.html") - 恶意页加载后立即执行:
window.opener.location = "https://fake-bank-login.com" - 用户以为仍在原网站,实际已在伪造页面中输入敏感信息
这种攻击无需 XSS 漏洞,仅依赖开放的 opener 引用,隐蔽性强、成功率高。
用 rel="noopener" 和 window.open() 的 noopener 特性主动防御
防范的关键是**切断 opener 引用**,让子窗口无法访问父窗口。标准做法是在打开链接或窗口时显式禁用 opener。
两种主流方式:
-
HTML 超链接场景:给
<a>标签添加rel="noopener"(推荐同时加noreferrer防止 Referer 泄露)<a href="https://third-party.com" target="_blank" rel="noopener noreferrer">外部链接</a> -
JavaScript window.open() 场景:在 features 字符串中加入
noopener(注意不是参数,是特性名)window.open("https://third-party.com", "_blank", "noopener,menubar=yes");
(Chrome 64+、Firefox 79+ 等现代浏览器已默认为noopener,但仍建议显式声明)
效果:启用后,子窗口中 window.opener 值为 null,任何对其的读写都会静默失败或报错,彻底阻断操控路径。
兼容性与补充防护建议
虽然 noopener 已广泛支持,但旧版 Safari(≤11.1)不识别该特性。为兼顾兼容性与安全性:
- 对必须兼容老 Safari 的场景,可在子页加载后立即执行:
window.opener = null;(需在 DOM 加载完成前尽早运行) - 父页面若需与子页通信,改用更安全的机制:如
postMessage()(支持跨域、可校验 origin)、URL 参数传值、localStorage + storage 事件监听等 - 避免在不可信上下文中使用
window.open();对用户生成内容中的链接,服务端应自动注入rel="noopener noreferrer"
不复杂但容易忽略——一条 rel="noopener" 就能堵住一个高危入口。


















