不加rel="noopener",target="_blank"就等于把原页面控制权白送给新页面;浏览器规范要求新页面window.opener默认指向原页window对象,跨域亦生效,可被恶意页面执行location跳转、dom篡改或postmessage通信,tiktok 2023年等已真实利用。

不加 rel="noopener",target="_blank" 就等于把原页面的控制权白送给新页面——不是风险,是既定行为。
为什么 target="_blank 默认危险?
浏览器规范明确要求:只要用了 target="_blank",新页面的 window.opener 就会指向原始页面的 window 对象。这不受同源策略限制,跨域也生效。
恶意页面可以立刻执行:
-
window.opener.location.href = "https://fake-login.example"—— 瞬间劫持你原来的标签页 -
window.opener.document.write(...)—— 替换你刚离开的页面 DOM -
window.opener.postMessage(...)—— 即使跨域也能通信(如果原页监听)
这不是理论漏洞,TikTok 2023 年、多个 CMS 插件都因此被实际利用过。
rel="noopener" 到底做了什么?
它不是拦截或过滤,而是在浏览器解析阶段就跳过设置 window.opener 这一步——新页面一加载,window.opener 就是 null,连读取都返回 null,更别说调用方法了。
关键细节:
- 必须和
target="_blank"同时出现才生效;单独写rel="noopener"浏览器直接忽略 - 旧版 Safari(≤12.0)和部分 Android WebView 完全不支持隐式
noopener,显式声明是唯一可靠方式 - Chrome ≥64 虽对干净的
target="_blank"做了隐式处理,但一旦你加了rel="nofollow"或rel="external",隐式机制立即失效
要不要加 rel="noreferrer"?
rel="noreferrer" 和 rel="noopener" 解决的是不同问题:
-
noopener是安全底线,切断 JS 引用 -
noreferrer是隐私补充,让 HTTP 请求头不带Referer字段,同时在多数现代浏览器中隐式启用noopener——但它不可替代前者
注意:
- 写成
rel="noreferrer noopener"看似一样,但某些 Markdown 渲染器或 CMS 只认第一个合法值,可能漏掉noopener - 如果后端依赖
Referer做简单校验(如图片防盗链),加noreferrer可能导致请求被拒 - 对外链、用户生成内容、富文本自动插入的链接,一律用
rel="noopener noreferrer";对需要Referer的合作方链接,至少保留rel="noopener"
框架和动态渲染里最容易漏的地方
模板里手写的 <a></a> 标签容易补上 rel,但以下场景几乎 100% 漏掉:
- Vue 中用
v-html渲染富文本,原始 HTML 没带rel,不会自动注入 - React 中用
dangerouslySetInnerHTML,同理 - 服务端拼接的评论区链接、CMS 后台导出的 HTML、Markdown 解析器自动加
target="_blank"却不加rel
最稳妥的做法,是在链接生成环节(比如服务端模板、富文本清洗函数、linkify 库配置)就强制注入 rel="noopener noreferrer",而不是指望前端运行时修补——后者根本不可靠。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











