rel不是form的合法属性,HTML标准仅允许其用于a、link等资源关联标签;form提交是请求动作而非资源引用,不触发rel的安全逻辑,真正需防护的是a标签和window.open()调用。

rel 不是表单(<form></form>)的合法属性,HTML 标准中它只作用于 <a></a>、<link> 等资源关联标签。试图在 <form></form> 上写 rel="noopener noreferrer" 完全无效,浏览器会忽略。
为什么 form 标签加 rel 没用
HTML 规范明确限定 rel 的使用上下文:rel 描述的是“当前文档”与“被链接资源”之间的关系,而 <form></form> 提交的是请求动作,不是资源引用。表单提交后页面跳转由 action 和 method 决定,不经过 window.opener 机制,也不触发 rel 相关的安全隔离逻辑。
-
<a href="..." target="_blank"></a>才是rel生效的唯一常见场景 -
<form target="_blank"></form>确实能新开窗口,但此时控制权在目标页的window.opener,而rel属性根本不会被解析——<form></form>不支持rel - 浏览器 DevTools 中检查该
<form></form>元素,能看到rel属性被保留为自定义属性(即rel=""),但毫无行为影响
form 外链跳转的真实风险点在哪
表单外链跳转本身不产生 window.opener 引用,但以下两种情况容易被误认为“需要 rel”:
-
提交后重定向到第三方页:比如
action="https://pay.example.com/submit",用户留在原页,新页由服务端返回;此时无 opener 风险,但需确保支付页 HTTPS、CSP 严格、不执行不可信 JS -
提交后前端 JS 跳转:例如
fetch()成功后执行window.open(result.url, "_blank")—— 这里真正要防护的是window.open()调用,不是<form></form>
如何安全地从 form 触发新窗口跳转
如果业务必须在表单提交后打开第三方页(如授权、支付结果页),正确做法是拦截默认提交,用 JavaScript 控制新开页并立即切断 opener:
document.querySelector('form').addEventListener('submit', async e => {
e.preventDefault();
const res = await fetch(this.action, { method: this.method, body: new FormData(this) });
const { url } = await res.json();
const newTab = window.open(url, '_blank');
if (newTab) newTab.opener = null; // 关键:手动置空
});
- 不能依赖
window.open(url, '_blank', 'noopener')—— 第三个参数是旧版特性字符串,现代浏览器已弃用且不生效 - 必须在
window.open()返回非 null 后立刻赋值opener = null,延迟执行(如放在setTimeout)可能被攻击利用 - 若目标页需回传数据,改用
postMessage(),不要依赖window.opener
最容易被忽略的细节
开发者常把 <a></a> 的防护经验错误迁移到 <form></form>,却漏掉真正危险的环节:动态生成的跳转链接。比如 CMS 导出的富文本中嵌入了 <a target="_blank"></a>,但没加 rel;或者后台模板拼接了裸 target="_blank" 的按钮,而表单本身只是个幌子。安全边界不在 form 标签,而在所有最终渲染出的 <a></a> 和所有 window.open() 调用点。

















