target="_blank"必须配rel="noopener noreferrer",否则新页面可通过window.opener篡改原页,且referer可能泄露敏感路径;两者缺一不可,动态插入链接需js补全,服务端白名单校验才是根本防护。

target="_blank" 必须配 rel="noopener noreferrer"
只写 target="_blank" 是危险的默认行为。新页面能通过 window.opener 重定向、篡改甚至窃取原页面状态,尤其在管理后台、支付页等场景极易被利用做 tabnabbing 攻击。
必须显式加上 rel="noopener noreferrer":
-
noopener切断window.opener引用,防止跨页控制 -
noreferrer不发送Referer头,避免泄露来源路径(比如含 token 的 URL) - 两者缺一不可:
rel="noopener"单独用仍会发 Referer;rel="noreferrer"单独用在部分浏览器(如旧版 Safari)下不阻断window.opener
正确写法:@#@#@#@#@#@#@#@#@#@0
动态插入的外链容易漏加防护
服务端模板渲染或 JS 拼接的链接(比如评论区用户输入、CMS 富文本输出)常忽略 rel 属性,变成裸 target="_blank"。
推荐在页面加载后统一补全:
- 用
document.querySelectorAll('a[target="_blank"]:not([rel])')找出所有未设rel的外链 - 过滤掉同域链接(
new URL(a.href).origin === location.origin),只对跨域链接加rel="noopener noreferrer" - 注意:不要用
innerHTML重写,直接操作a.rel属性更安全
示例片段:
document.querySelectorAll('a[target="_blank"]:not([rel])').forEach(a => {
if (new URL(a.href).origin !== location.origin) {
a.rel = 'noopener noreferrer';
}
});
href="javascript:void(0)" 不等于安全
用 href="javascript:void(0)" 替代真实链接,常被误认为“无害”,但它本身是伪协议,且掩盖了真实交互意图。
问题在于:
- 无障碍支持差:屏幕阅读器可能无法识别其可操作性
- 语义丢失:搜索引擎和爬虫无法理解该元素用途
- 若后续绑定 click 时没处理好,仍可能触发意外跳转(比如事件冒泡到父级带
href的容器) - 比
href="#"稍好,但不如直接移除href+ CSS 模拟链接样式(cursor: pointer+text-decoration: underline)
白名单校验比前端防护更重要
前端加 rel、禁右键、混淆 HTML,都挡不住源码查看。真正有效的防护落在服务端。
当页面需渲染用户提交的外链(如富文本、评论、配置项)时:
- 强制校验域名:只允许白名单中的域名出现在
href中(如github.com、wikipedia.org) - 协议限制:拒绝
javascript:、data:、vbscript:等危险协议 - 剥离未声明属性:用 HTML 白名单净化器(如 DOMPurify)处理输入,而非简单正则替换
- 敏感操作跳转前加中间页确认,尤其是涉及账号、资金、权限变更的外链
记住:HTML 被浏览器下载即暴露。你花十分钟加的 rel 属性,能防住脚本注入,但防不住人眼阅读——该藏的逻辑和数据,从来就不该出现在 HTML 里。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











