必须配rel="noopener",否则存在opener劫持风险:不加时新页面可通过window.opener.location静默跳转原页面至钓鱼站;现代浏览器不会自动切断opener,显式声明是唯一可靠方式。

target="_blank" 必须配 rel="noopener",否则存在 opener 劫持风险
不加 rel="noopener" 的 target="_blank" 链接,等于把原页面的 window 控制权交给新页面。攻击者只需一行 window.opener.location = 'https://fake-login.example' 就能静默劫持你的标签页——用户切回来时看到的已是钓鱼页面。
现代浏览器(Chrome 88+、Firefox 79+、Safari 14.1+)**不会自动切断 opener**,这是明确的设计选择:是否隔离上下文,由开发者显式声明。所谓“浏览器默认加 noopener”是误传;实际只在部分 Chromium 行为中做了隐式补全,但不可依赖。
- 旧版 Safari(≤15.4)完全不识别
rel="noreferrer"的 opener 切断能力,只认rel="noopener" - IE 和 Edge Legacy 不支持
rel="noopener",但已无实际维护价值,可不作兼容 - 富文本编辑器或 CMS 输出的链接常自动带
target="_blank",但极少自动补rel,需服务端或前端做清洗
rel="noopener noreferrer" 是当前最稳妥的组合写法
rel="noopener" 和 rel="noreferrer" 各管一事:noopener 切断 window.opener 引用,noreferrer 禁发 Referer 请求头。二者必须共存,且顺序建议为 noopener noreferrer——部分 Markdown 渲染器或 HTML 解析器会按顺序取第一个合法值,颠倒可能意外降级。
-
rel="noreferrer"在 Chrome/Firefox 中会隐式触发 noopener 效果,但 Safari 15.4 之前不保证,所以不能省略显式noopener - 如果业务强依赖
Referer(如来源统计),至少保留rel="noopener",不要为 Referer 放弃安全底线 -
rel="nofollow"或rel="external"对安全零贡献,加了也白加,还可能误导后续维护者
哪些场景下 rel="noopener" 无效?
rel="noopener" 的作用机制依赖“新浏览上下文”的创建,它只对 <a></a> 标签 + target="_blank"(或非 _self 的 target)生效。其他写法全是无效空转:
-
<link rel="noopener" href="...">:语法合法,但浏览器静默忽略 -
<a href="..." target="_self"></a>或未写target:页面仍在当前上下文跳转,不存在 opener 风险,加noopener多余 -
<a href="..." target="_blank" rel="noopener"></a>但目标是同源地址:技术上无害,但增加不必要的上下文隔离开销 -
window.open(url, '_blank', 'noopener'):这里的noopener是旧版弹窗特性参数,和 HTML 的rel完全无关,也不起作用
动态生成链接时如何确保安全?
服务端渲染或富文本输出中,不能指望用户手写 rel。必须在输出前做标准化处理:
- 对所有含
target="_blank"的<a></a>标签,强制注入rel="noopener noreferrer"(若已有rel,则合并去重) - 前端 JS 动态创建链接时,必须同步设置:
el.rel = 'noopener noreferrer',不能只靠 HTML 模板 - 使用
window.open()打开跨域页面后,应立即执行newTab.opener = null,这是唯一可靠方式 - Lighthouse、ESLint(如
jsx-a11y/anchor-rel)等工具会直接报出漏掉noopener的链接,建议接入 CI 流程卡点
真正关键的不是写了几个 rel 值,而是理解 noopener 的触发边界:它只在 <a></a> + target="_blank" 组合下才真实生效,且 Safari 15.4 是兼容性分水岭——此前版本必须显式同时写两个值,缺一不可。











