必须为 target="_blank" 添加 rel="noopener" 以防止 Tabnabbing 攻击、保障原页面安全并提升性能;对外链推荐 rel="noopener noreferrer",window.open() 需手动设 opener=null。

target="_blank" 不加 rel="noopener" 会立刻暴露原页面
只要用了 target="_blank",新标签页的 window.opener 就默认指向你的当前页面 window 对象。恶意站点不需要同源、不需要 XSS 漏洞,只要执行 window.opener.location.href = "https://fake-login.example",就能在你用户毫无察觉时把原标签页重定向到钓鱼页。
这不是假设——Tabnabbing 是真实攻击链,2019 年起已被主流安全工具(如 Lighthouse)标记为中高危项。Chrome 和 Firefox 的 DevTools 已不再主动提示缺失 rel="noopener",但攻击者根本不会等你打开控制台。
- 管理后台、支付页、登录态页面必须加,没商量
- CMS、Markdown 渲染器、富文本编辑器导出的 HTML 很容易漏掉,要检查输出环节
- 服务端模板拼接链接时硬编码
target="_blank"却不带rel,是高频漏洞点
rel="noopener" 和 rel="noreferrer" 到底该用哪个
rel="noopener" 是底线:它让新页面的 window.opener 为 null,彻底切断控制链;rel="noreferrer" 是额外选项:它同时抑制 Referer 头发送,但会带来副作用——部分分析平台(如 Google Analytics)可能丢失来源追踪。
现代浏览器(Chrome ≥64、Firefox ≥79、Edge ≥79、Safari ≥12.1)中,rel="noopener" 已隐式包含 noreferrer 行为,但显式写全更可靠。
- 对外链、用户生成内容、第三方跳转,推荐写
rel="noopener noreferrer" - 同域内链接(如
/help)且你完全信任目标 JS,可只用rel="noopener" - 若需保留 Referer(例如内部埋点),不要加
noreferrer,但noopener仍不可省
window.open() 也要手动断开 opener 引用
用 JavaScript 动态开新窗口时,rel 属性无效,必须显式置空 opener:
const newTab = window.open('https://example.com', '_blank');
if (newTab) {
newTab.opener = null;
}
注意:不能只靠 window.open(url, '_blank', 'noopener') —— 这个 noopener 是旧版弹窗特性参数,和 HTML 的 rel 无关,也不起作用。
- 所有通过
window.open()打开的跨域页面都应立即设opener = null - 如果新窗口需要和原页通信,改用
postMessage(),而不是依赖window.opener - 旧版 Safari(≤11.0)不支持
rel="noopener",但支持rel="noreferrer",可降级兜底
加了 rel="noopener" 还能提升页面性能
不加 rel="noopener" 时,浏览器为支持 window.opener 同步访问,会强制将两个标签页放在同一渲染进程里。这意味着新页面的 JS 长任务(比如大量计算、阻塞循环)会直接拖慢原页面的主线程——滚动卡顿、随机数生成掉帧、文本选中延迟都是典型现象。
加上后,Chromium 系列浏览器会为新页面分配独立进程,原页面保持 60fps 响应能力。这个性能收益在后台管理系统、实时数据看板等场景尤为明显。
- 性能提升不是副作用,而是浏览器明确设计的行为
- Firefox 采用不同进程模型,影响稍小,但仍建议统一加上
- 别等用户反馈“点外链后页面变卡”,这很可能就是没加
rel="noopener"
target="_blank" 却不补 rel。安全不是加一次就结束,而是每次插入链接时,都要下意识敲出那几个字母。

















