rel="noopener" 是 target="_blank" 的安全底线,它在解析阶段直接使新页面 window.opener 永远为 null,防止恶意页面通过 window.opener 劫持原页面;旧版浏览器及动态生成链接(如 markdown、富文本、模板拼接)易遗漏,隐式 noopener 并不可靠。

rel="noopener" 是 target="_blank" 的安全底线,不加它,目标页面就能用 window.opener.location.replace() 静默劫持你的原页面——这不是漏洞预警,是浏览器明确允许的行为。
为什么 target="_blank 默认暴露 window.opener
浏览器规范要求:只要没声明 rel="noopener",新标签页的 window.opener 就必须指向原始页面的 window 对象。跨域也生效,且不受同源策略限制。
- 恶意页面一打开就能执行
window.opener.location.href = "https://fake-login.example",你切回原标签时看到的就是钓鱼页 -
window.opener.document.title = "Session expired"可伪造提示诱导输入密码 - 哪怕原页面已关闭,只要新页还开着,
window.opener引用在部分浏览器中仍可能有效(取决于 GC 策略)
rel="noopener" 到底切断了什么
它不是运行时拦截,而是在浏览器解析 <a></a> 标签阶段,直接跳过设置 window.opener 字段这一步——新页面的 window.opener 永远为 null。
- 加了之后,在新页控制台执行
window.opener.location会返回null,调用方法直接报错或静默失败 -
rel="noreferrer"不影响window.opener,它只管 HTTP 请求头里的Referer字段 - 旧版 Safari(≤11.0)、IE11 完全不认
rel="noreferrer"对window.opener的影响,不能替代noopener
动态生成链接时最容易漏掉的三个地方
风险不在手写 HTML,而在自动化输出环节——这些地方几乎从不触发开发者警告,但 Lighthouse 会标高危。
- Markdown 渲染器自动给外链加
target="_blank",但默认不补rel属性 - 富文本编辑器导出的 HTML 未做
rel值过滤或重写,用户插入的链接直接裸奔 - 服务端模板拼接链接时硬编码了
target="_blank",却忘了合并已有rel值(比如已有rel="nofollow",直接覆盖成rel="noopener"就丢了语义)
别信“现代浏览器已默认修复”这种说法
Chrome ≥64、Firefox ≥79 虽有隐式 noopener 行为,但只在 rel 属性完全为空时才生效;一旦你写了 rel="nofollow" 或 rel="external",隐式机制立即失效。
- Safari ≤12.0 完全不支持隐式
noopener,必须显式声明 - Android 8.0 内置 WebView 等老旧环境也不生效
- 某些 Markdown 解析器按空格分割
rel值,写成rel="noreferrer noopener"可能只取第一个值,结果只生效noreferrer
真正难的不是加一行属性,而是确保每个动态出口——CMS 输出、评论渲染、广告 SDK 注入、甚至 window.open() 调用——都守住这个引用切断逻辑。漏掉任意一个,就等于在生产环境留了一扇没锁的门。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











