本文目录导读:

Referer校验是一种常见的安全机制,用于判断请求的来源页面是否合法。Referer头本身是由客户端(浏览器或HTTP客户端)发送的,恶意攻击者可以轻易修改或伪造,因此它防伪造的能力非常有限。
针对“如何防伪造”这个问题,正确的理解应该是:Referer校验并不能有效防止伪造,它更多是作为一道浅层、辅助性的检查手段。 下面我们详细拆解其原理、为什么防不住、以及如何通过其他措施来弥补。
Referer校验的基本原理
服务器通过检查HTTP请求头中的Referer字段(拼写错误的历史遗留,正确应为Referrer),来判断请求是否来自一个预期的、合法的来源页面。
示例:
- 合法场景:用户从
https://mybank.com/transfer提交转账请求,服务器校验Referer: https://mybank.com/transfer,通过。 - 攻击场景:攻击者在
https://evil.com/构造一个伪造的转账表单,诱导用户提交,服务器校验Referer: https://evil.com/,失败,拦截。
为什么Referer容易被伪造?(防伪造的天然缺陷)
-
客户端可控:
Referer头完全由客户端(浏览器、curl、自己写的HTTP客户端等)生成和发送,任何使用网络库(如Python的requests、curl命令)发起的请求,都可以在代码中任意设置Referer字段,甚至取消发送。 -
浏览器插件/开发者工具:用户可以通过浏览器开发者工具、Fiddler、Burp Suite等代理工具,轻松修改请求头中的
Referer。 -
关键漏洞:Referrer Policy:为了避免泄露隐私,现代浏览器引入了
Referrer Policy,网站可以设置meta name="referrer"或通过HTTP头Referrer-Policy来指示浏览器不发送或仅发送部分Referer头。no-referrer:浏览器根本不会发送Referer头。same-origin:仅在同源请求时发送。strict-origin-when-cross-origin:跨域请求只发送源(protocol + host + port),不发送完整路径。
这意味着,一次合法的、来自用户真实点击的请求,也可能因为Referrer Policy而没有携带你期望的完整
Referer头(甚至完全没有),这使得依赖Referer进行校验的服务器会误杀合法流量。
既然防伪造能力弱,为什么还要用?
因为成本低、易部署、能防住最基础的攻击(CSRF),在早期Web应用中,它作为一个简单有效的初始屏障,可以挡住大多数“脚本小子”级别的攻击,但对于有明确动机的、技术能力较强的攻击者,它形同虚设。
如何真正“防伪造”?——放弃单纯依赖Referer
既然Referer无法可靠防伪造,安全防护需要采用更健壮的方案,尤其是在防跨站请求伪造(CSRF) 场景下,以下是更可靠的替代和补充方案,它们共同构成了现代Web应用的安全防线,并且不再将Referer作为核心依赖。
核心方案:CSRF Token(跨站请求伪造令牌)
这是目前业界标准的、最有效的防CSRF方案。
- 原理:
- 服务器生成一个唯一的、随机的、不可猜测的Token(通常是长字符串),存储在用户的会话(Session)或Cookie中。
- 当服务器返回包含表单或发送请求的页面时,会将这个Token以隐藏字段的形式嵌入页面(
<input type="hidden" name="csrf_token" value="xxxxxxxxxx">)。 - 当用户提交请求时,客户端需要将Token连同其他数据一起发送回服务器。
- 服务器验证收到的Token与会话中存储的Token是否匹配。
- 为什么防伪造:
- 攻击者无法获取用户的Token,因为他构造的恶意页面无法知道服务器为用户本次会话生成的唯一Token是什么。
- Token与用户Session绑定,一次一用或有时效性,爆破难度极高。
核心方案:SameSite Cookie属性
这是现代浏览器提供的最简单、最强大的防CSRF机制,可以理解为浏览器原生帮你校验来源。
- 原理:服务器在设置Cookie时,可以添加
SameSite属性:Set-Cookie: sessionid=xxx; SameSite=Lax。Strict:最严格,浏览器只在由当前网站发起的顶级导航请求(如点击链接)时才发送该Cookie。任何来自其他网站(evil.com)发起的请求(如通过<form>、<img>、fetch构造的请求)都不会携带该Cookie。Lax(推荐):平衡安全与可用性,允许顶级导航请求(如点击链接、GET表单)发送Cookie,但禁止跨站POST表单请求发送Cookie,这能防御绝大多数CSRF攻击。None:关闭此保护,需要同时设置Secure(仅HTTPS)。
- 为什么防伪造:攻击者伪造的请求虽然能发出去,但因为不携带用户的Session Cookie(认证凭据),这个请求对于服务器来说等同于未登录状态,毫无意义。
辅助方案:自定义请求头
要求发起非简单请求(如POST/PUT/DELETE)时,必须携带一个自定义的HTTP头(X-Requested-With: XMLHttpRequest)。
- 原理:跨域请求时,浏览器对于非简单请求会先发送一个预检请求(OPTIONS),且自定义请求头不能通过HTML表单或简单的
<img>标签发送,攻击者无法通过普通的CSRF攻击构造出包含自定义请求头的请求(除非利用CORS配置错误或XSS漏洞)。 - 为什么防伪造:攻击者无法通过
<form>或<img>发送自定义头,这要求前端必须通过JavaScript(如fetch、XMLHttpRequest)来发送请求,增加了攻击者构造恶意站点的难度。
| 方案 | 能否被伪造? | 防护强度 | 推荐度 |
|---|---|---|---|
| Referer校验 | 极易被伪造 | 极低(辅助手段) | ❌ 不推荐作为唯一防御 |
| CSRF Token | 极难被伪造(需配合XSS) | 高 | ✅ 核心防御(必选) |
| SameSite Cookie | 浏览器原生防护,不可篡改 | 高 | ✅ 核心防御(必选,现代应用首选) |
| 自定义请求头 | 难以通过传统CSRF伪造 | 中 | ✅ 补充防御 |
最终结论:
不要试图通过加固Referer校验来防伪造。 它的可靠性由客户端环境决定,且存在合法的缺失场景,正确做法是放弃依赖Referer作为主要安全校验手段,转而采用CSRF Token + SameSite Cookie的组合拳。Referer可以作为一道辅助日志审计(记录来源)或最低限度的防护层,但绝不能将其作为安全边界。
如果你仍在开发或维护依赖Referer校验的老系统,建议尽快迁移到以上更健壮的方案,这远比试图“加强”一个先天不足的机制要安全得多。