base标签不是安全机制,不校验、不过滤、不转义内容;其href若被用户可控且未白名单校验(如拼入javascript:协议),虽自身不执行js,但可能劫持相对路径导致协议拼接型xss或资源加载失控。

base标签本身不防注入,但写错会放大XSS风险
直接说结论:<base> 标签不是安全机制,它不校验、不过滤、不转义任何内容。所谓“预防相对路径解析注入”,其实是误读——<base> 只改变相对 URL 的解析起点,而注入攻击(如 onerror、javascript: 协议)发生在属性值被浏览器执行时,和 base 无关。
真正危险的是:你本想用 <base href="/app/"> 统一资源路径,却因 href 值被用户可控或未校验,导致整个页面的相对链接基准被劫持。比如服务端模板错误地把用户输入拼进 href:<base href="%24%7Buser_input%7D">,而 user_input 是 "javascript:alert(1)",浏览器虽不会执行它(href 不触发 JS),但若后续有 <a href="x"></a> 被解析为 javascript:alert(1)x,就可能触发协议拼接型 XSS。
-
<base href>的 href 值必须是绝对 URL 或合法根相对路径(如/myapp/),其他值(如./、javascript:、data:)会被浏览器静默忽略,此时 fallback 到文档 URL,反而让攻击面更不可控 - 若服务端动态注入 href,必须对值做白名单校验:只允许
https?:协议、//协议相对路径、或以/开头且结尾带斜杠的路径(如/admin/) - 禁止把未过滤的用户输入(如 URL 参数、数据库字段)直接插进
href属性;哪怕只是用于 base,也属于属性注入高危场景
哪些地方容易把 base 变成注入跳板
常见出问题的不是前端手写,而是服务端或构建流程中“看似安全”的动态拼接:
- Django 模板里写
<base href="%7B%7B%20request.GET.base%20%7D%7D">,没校验base参数,攻击者传?base=//evil.com/就能把所有相对资源引向恶意域名 - Gin 或 Gin-like 框架中,用
c.Param("path")拼 base href,而 path 是../static/—— 浏览器虽忽略该值,但开发者误以为生效,实际资源仍按当前 URL 解析,导致路径混乱+404,掩盖真实漏洞 - Vite 构建时配置
base: process.env.BASE_URL,但 CI 环境变量未设或设为空字符串,最终生成<base href="">,规范要求此情况 fallback 到文档 URL,但不同浏览器处理细节不一,可能引发兼容性 XSS 边界问题
真正要防的不是 base,而是所有属性值里的协议和路径
比起纠结 <base>,优先堵死以下三类属性注入点:
-
src/href/formaction:必须用new URL(value)校验 protocol,只放行http:、https:、/(根路径) -
onerror/onload/onclick:这类事件处理器属性绝不能由用户输入拼入;应改用addEventListener+ 白名单函数名 -
data-自定义属性:看似安全,但若后续 JS 用el.dataset.xxx拼进eval()或innerHTML,一样触发 XSS
例如,<img src="user_avatar" onerror="loadFallback('${user_avatar}')"> 中的 ${user_avatar} 若含单引号或闭合引号,就能逃逸出字符串上下文。
验证 base 是否被恶意篡改的实操方法
上线前必须检查两件事,缺一不可:
- 打开控制台,执行
document.baseURI—— 返回值必须是预期的绝对 URL 或合法根路径,且不能含javascript:、data:、vbscript:等可执行协议 - 在 Network 面板中挑一个 404 的资源请求,看它的「Initiator」是不是 HTMLParser;如果是,说明 base 生效了但 href 值非法;如果不是,说明 base 被忽略,问题出在位置或格式(比如没放
最上方、或写了两个<base>)
最易被忽略的一点:base 的安全性不取决于你写了什么,而取决于谁写了它、怎么写的、以及写完之后有没有被其他流程(如 CDN 重写、代理注入、前端路由拦截)悄悄覆盖或修改。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











