使用target="_blank"时必须显式添加rel="noopener noreferrer",否则存在安全漏洞,新页面可通过window.opener篡改原页面;该防护仅适用于HTML场景,window.open()需手动设opener=null。

target="_blank"不加rel="noopener"就是安全漏洞
只要用了target="_blank",新页面默认能通过window.opener直接修改原页面地址、清空DOM,甚至触发卡顿。这不是理论风险——TikTok 2023年就被利用过。Chrome 88+虽隐式补noopener,但Safari和Firefox仍完全依赖显式声明,不能赌兼容性。
常见错误现象:
-
<a href="https://evil.com" target="_blank">点我</a>(缺rel) -
rel="NOOPENER"或rel="no-opener"(大小写或连字符错) -
rel="noopener noreferrer "末尾带空格(属性值失效)
rel="noopener noreferrer"必须和target="_blank"一起出现才生效
rel="noopener noreferrer"只在创建新浏览上下文时起作用,包括:<a target="_blank">、<form target="_blank">、window.open(url, "_blank")这三类场景。单独写rel属性,浏览器直接忽略。
使用场景与参数差异:
立即学习“前端免费学习笔记(深入)”;
- 仅需防劫持:用
rel="noopener"已足够 - 兼顾隐私(如防Referer泄露):叠加
noreferrer,推荐组合rel="noopener noreferrer" - 顺序不能颠倒:部分Markdown渲染器或CMS解析器按顺序取第一个合法值,
rel="noreferrer noopener"可能只认noreferrer -
rel="nofollow"对安全零贡献,别混着加来“凑数”
服务端和富文本是高危重灾区
手动写HTML容易补全,但真实风险集中在动态生成环节:富文本编辑器(如CKEditor)、CMS模板、评论区自动识别URL、React/Vue的v-html或dangerouslySetInnerHTML渲染内容——这些地方常自动加target="_blank",却从不自动补rel。
实操建议:
- 服务端输出前统一匹配
<a[^>]*target="_blank"[^>]*>,自动注入rel="noopener noreferrer"(若原无rel或不含noopener) - 若已有
rel="nofollow",应合并为rel="nofollow noopener noreferrer",而非覆盖 - 检查第三方Markdown库(如
marked)是否支持rel白名单配置,否则需前置清洗 - Lighthouse扫不出这类问题,得靠人工查输出HTML或用正则批量 grep
window.open()不能靠rel属性防护
rel是HTML属性,对JavaScript主动开窗完全无效。window.open(url, "_blank", "noopener")是错的——noopener不是合法的features字符串参数。
正确做法:
- 同源且兼容可控:先
window.open(),再立即设newTab.opener = null - 跨域或旧版Safari兼容要求高:改用
location.replace()跳转 + 新窗口监听,或放弃JS开窗,回归纯HTML - 不要只写
window.open(url)或window.open(url, "_blank"),默认保留window.opener引用
真正容易被忽略的是:window.open()调用后那一行opener = null——它不在HTML里,也不走服务端模板,必须在JS执行路径中显式插入,漏掉就等于裸奔。



















