rel="noopener"是堵住浏览器默认开启的window.opener控制通道,不加它target="_blank"会使新页面跨域劫持原页面,引发tabnabbing攻击并拖慢性能。

rel="noopener" 不是“增强安全”,而是堵住一个浏览器明确允许的、默认开启的控制通道。不加它,target="_blank" 就等于主动把原页面的 window 对象交到新页面手上。
为什么 target="_blank 默认危险?
新标签页打开后,它的 window.opener 会直接指向原始页面的 window 对象——这不受同源策略限制,跨域也生效。
恶意页面可以立刻执行:
-
window.opener.location.href = "https://fake-login.example"—— 原页面无声跳转 -
window.opener.document.write(...)—— 替换你刚离开的页面 DOM -
window.opener.postMessage(...)—— 如果你监听了 message,可能被诱导泄露 token
这不是理论推演,是 Tabnabbing 攻击链的标准起点。2023 年 TikTok 就因此被利用过。
rel="noopener" 到底切断了什么?
它强制让新页面的 window.opener 为 null,彻底断开双向引用。关键点:
- 不是“建议加”,是现代浏览器对
target="_blank"的隐式默认行为(但显式声明才可靠) -
rel="noreferrer"在旧版 Safari(≤11.0)中不保证切断window.opener,不能替代noopener -
rel="noopener"不影响 Referer 头;如需隐藏来源,得额外加noreferrer或用referrerpolicy
哪些地方最容易漏掉 rel="noopener"?
风险不在手写 HTML,而在动态生成环节:
- Markdown 渲染器自动加
target="_blank",但不补rel属性 - 富文本编辑器导出的 HTML 未过滤或重写
rel - 服务端模板拼接链接时硬编码了
target="_blank",却忘了rel - 已有
rel="nofollow"的外链,直接覆盖成rel="noopener",丢失原有语义
对外链、用户生成内容、CMS 自动生成的链接,一律强制添加——没有例外。
性能损耗也是真实存在的
不加 rel="noopener" 会让浏览器维持两个页面间的隐式绑定,导致原页面无法进入后台冻结态:
- 定时器、动画帧、fetch 请求被延迟或降频
- 实测 Chrome 中内存占用升高 12%~18%
- 页面切换响应延迟从 14ms 升至 86ms
这个性能拖累在低端设备或标签页较多时尤为明显——你点开一个广告,自己页面突然卡顿,大概率就是这个原因。
最常被忽略的不是语法,而是逻辑覆盖:单引号、换行分隔的 target、已存在其他 rel 值的合并处理、内链误加 noreferrer 导致分析归因失效……安全不是加一次就完事,是每个动态出口都得守住这一关。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











