rel="noopener"防止Tabnabbing攻击,核心是强制新页面window.opener为null,切断其通过window.opener劫持原页面的能力;不加它,target="_blank"会使新页面获得对原页面的完全控制权。

只加 target="_blank" 会触发 tabnabbing 漏洞
浏览器默认让新打开的页面通过 window.opener 访问并控制原页面,哪怕只是跳转到一个普通外链。攻击者只需在目标页执行 window.opener.location = 'https://fake-login.com',就能把用户正在操作的后台页面悄悄替换成钓鱼页——而用户毫无感知。
这不是理论风险:Chrome ≥64、Firefox ≥79、Safari ≥12.1 等现代浏览器虽已对 target="_blank" 隐式启用 noopener,但旧版 Safari(
所以不能依赖“浏览器自己会处理”,必须显式声明:
-
rel="noopener"是底线:强制将新页面的window.opener设为null,彻底切断控制链 - 不加
noopener就等于裸奔,哪怕只用于跳转文档或帮助页 - 如果链接还带
target="_blank",却没写rel="noopener",就属于高危配置
rel="noreferrer" 不是“伪造 Referer”,而是彻底移除
你无法用前端手段把 Referer 改成 rock&roll.com 或任意值——所有尝试(fetch() + referrerPolicy、meta refresh、iframe 中转)在跨域跳转中均被浏览器明确禁止。W3C 规范只允许两种状态:继承原始来源,或完全不发送。
rel="noreferrer" 的作用就是后者:目标服务器收到的请求头里压根没有 Referer 字段(不是空字符串,是字段缺失),document.referrer 在新页面也为空。
它还有个隐藏好处:自动带上 noopener 行为,所以单独写 rel="noreferrer" 已能兼顾 opener 安全和 Referer 隐藏。
- 适用于所有外链、用户生成内容、第三方广告位等不可信跳转场景
- 服务端日志、PHP 的
$_SERVER['HTTP_REFERER']、Node.js 的req.headers.referer均收不到该字段 - Google Analytics 等前端埋点会丢失来源归因,这是代价,不是 bug
要不要加 nofollow?看用途,不是看 Referer
rel="nofollow" 和 Referer 完全无关。它只影响搜索引擎是否将该链接作为权重传递路径,对 HTTP 请求头、window.opener、隐私控制零影响。
如果你希望外链不被爬虫索引(比如付费推广、未审核评论),可以叠加使用;但若只是想隐藏来源或防劫持,nofollow 属于冗余属性。
- 组合写法推荐:
rel="noopener noreferrer"(安全+隐私)或rel="noopener noreferrer nofollow"(再加 SEO 控制) - 不要写
rel="noreferrer nofollow"却漏掉noopener——虽然noreferrer隐含noopener,但显式写出更可靠、可读性更强 - 别指望
nofollow能“伪装” Referer,它连请求头都不碰
哪些地方容易漏掉 rel 属性?
最容易被忽略的是模板引擎动态拼接的链接,比如 CMS 后台、评论系统、Markdown 渲染器输出的 HTML。它们常硬编码 target="_blank",却没同步注入 rel。
另一个盲区是富文本编辑器导出的内容,或从 Word/PDF 粘贴进来的链接——这些往往保留原始属性,但不带 rel。
- 静态站点生成器(如 Hugo、Jekyll)需检查 link shortcode 或插件是否默认补全
rel - React/Vue 项目中,用
dangerouslySetInnerHTML或v-html渲染用户输入时,必须后置清洗,自动补上rel="noopener noreferrer" - 服务端渲染(SSR)场景下,若链接由后端拼接(如 PHP
echo '<a href="'.%24url.'" target="_blank">';</a>),必须人工补上rel,不能指望前端 JS 修复
rel="noopener noreferrer" 这八个字要出现在每个带 target="_blank" 的外链上,不是可选项,是上线前必须过的一道卡口。

















