必须同时写target="_blank"和rel="noopener noreferrer",仅用前者会使新页面通过window.opener劫持原页面url、读取dom或拖慢性能,且旧版safari中只写noreferrer无法阻止opener访问,二者缺一不可。

必须同时写 target="_blank" 和 rel="noopener noreferrer",只写前者在现代浏览器里可能被降级为当前页跳转,还存在安全风险。
为什么只加 target="_blank" 不行
浏览器确实会新开标签页,但新页面能通过 window.opener 直接控制原页面——比如改掉原页 URL、读取 DOM、拖慢主线程。这不是理论漏洞,而是默认行为。
- 点开外部链接后切回原页,发现地址已跳转 → 典型
window.opener.location劫持 - 原页面明显卡顿,尤其新页跑 heavy JS → 两个页面共享渲染进程
- 控制台报
Blocked a frame with origin https://www.php.cn/link/263b1243ca2dbeb358777ceabc4a2e4c from accessing a cross-origin frame→ 浏览器正在拦截攻击,说明风险真实存在
rel="noopener noreferrer" 必须两个值一起写
漏掉 noopener 就等于没关后门;只写 noreferrer 在 Safari 旧版本里完全不防 window.opener 劫持。
- 顺序无所谓:
rel="noreferrer noopener"和rel="noopener noreferrer"效果一样 - 拼错无效:
ref="noopener"(少一个l)或rel="noopenner"都白搭 - 内部链接别乱加:像
/about或#section2加了反而影响 SPA 路由或锚点跳转
动态生成链接时怎么避免漏掉 rel
用字符串拼接 HTML(比如 innerHTML += '@#@#@#@#@#@#@#@#@#@0')最容易丢掉 rel 属性,必须改用 DOM API 显式赋值。
- 创建元素:
const link = document.createElement('a') - 依次设置:
link.href = 'https://example.com'、link.target = '_blank'、link.rel = 'noopener noreferrer' - 插入前检查:
console.log(link.outerHTML)确认三项都在 - 批量处理外部链接:
document.querySelectorAll('a[href^="http"]:not([href*="yoursite.com"])'),再 forEach 添加属性
别用 <base target="_blank"> 图省事
它会让所有没显式设 target 的链接都新开,但无法为每个链接单独配 rel,结果是全部暴露在 window.opener 风险下。
更麻烦的是,CMS 富文本编辑器常自动过滤 rel 属性,或者框架(如 React/Vue)在 SSR 渲染时漏掉它——这些地方最容易出问题,得手动补全。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











