在现代Web应用中,服务端需要对请求进行合法性校验,以防止恶意攻击(如跨站请求伪造CSRF)。
早期一种常见的做法是依据HTTP请求头中的Origin或Referer信息来判断请求来源,只放行来自可信站点的请求。然而,这种机制存在明显缺陷,因此逐渐被更安全的方案,如CSRF Token所取代。
一、基于Origin/Referer的校验机制及其局限性
1. 工作原理
服务端检查每个请求的Origin或Referer头:
- 若该头的值在允许的域名列表内,则放行;
- 若头信息缺失或域名不符,则拒绝请求。
这种方法的逻辑是:正常浏览器请求会自动带上当前页面的来源,因此可以借此区分“本站内发起的请求”和“外部站点发起的跨站请求”。
2. 主要缺点
(1)请求头可以被伪造
Origin和Referer完全由客户端(浏览器、脚本、命令行工具)控制。攻击者可以轻易构造带有任意Referer值的请求,从而绕过服务端的来源校验。例如,使用curl直接添加Referer: 即可骗过服务器。
这使得该机制只能防御最基础的、不修改请求头的攻击,防护强度较低。
(2)搜索引擎与攻击者之间的两难困境
为了SEO,网站必须放行搜索引擎爬虫(如Googlebot)的请求。但服务器通常只能通过User-Agent或Referer来识别这些爬虫,这就带来了两种风险:
- 伪造爬虫身份:攻击者将自己的
User-Agent改为Googlebot,同时清空Referer,就可能绕过限制; - 利用搜索引擎来源:如果服务器信任来自
google.com的Referer,攻击者可搭建恶意站点,伪造该Referer诱导用户点击,从而发起跨站请求。
核心问题在于:所有关键校验字段都由客户端提供,服务端无法真正验证其真实性。
二、更安全的方案:CSRF Token
为了解决上述问题,现代Web应用普遍采用CSRF Token机制,它将校验依据从“请求来源”转移到“服务端与前端预先协商的、不可预测的密钥”。
1. 工作原理
(1)建立会话时生成Token
当用户首次访问页面或登录成功后,服务端生成一个随机、不可预测的字符串(CSRF Token),并将该Token与当前用户的会话(Session)绑定。同时,Token被安全地写入前端页面,例如放在表单的隐藏字段中,或存储在<meta>标签内供JavaScript读取。
(2)发起请求时携带Token
当用户执行需要保护的敏感操作(如修改密码、转账)时,前端自动从页面中提取Token,并将其放入请求的特定位置(通常是请求头X-CSRF-Token,或POST表单字段)。这一过程对正常用户无感。
(3)服务端校验Token
服务端收到请求后,取出请求中的Token,并与会话中保存的Token进行比对:
- 一致 → 请求确实来自网站自身页面且由用户主动触发,放行;
- 不一致或缺失 → 拒绝请求。
2. CSRF Token为何更安全
- 不可预测性:Token为服务端生成的随机值,攻击者无法提前构造包含正确Token的恶意请求。
- 绑定会话:每个用户的Token与会话唯一绑定,无法在其他会话下复用。
- 不依赖客户端上报的来源:即便攻击者伪造
Origin或Referer,缺少有效Token的请求依然会被拦截。 - 对搜索引擎友好:爬虫不执行页面脚本或提交表单,不会携带Token,因此不会被误拦;正常用户请求则因正确携带Token而正常放行。
三、现代Web中的组合防护
虽然CSRF Token能够有效防御CSRF攻击,但在实际工程中,为了兼顾安全性与用户体验,通常会组合使用多种防护手段:
- SameSite Cookie属性:将Cookie设置为
SameSite=Lax或Strict,可阻止大多数跨站请求自动携带Cookie,从浏览器层面减轻CSRF风险。 - 双重Cookie验证:将Token同时放在Cookie和请求头中,服务端校验两者是否一致,适用于前后端分离架构。
- API网关/签名机制:对于非浏览器的API调用(如移动端、第三方服务),使用更严格的签名算法(如OAuth、HMAC)确保请求的完整性和来源可信。
四、总结
- 基于
Origin/Referer的来源校验虽然实现简单,但其安全性严重依赖客户端上报的信息,容易被伪造,且在允许搜索引擎时存在明显绕过风险。 - CSRF Token机制通过服务端生成并校验随机密钥,从根本上解决了跨站请求伪造问题,成为现代Web安全防护的重要基石。在实际应用中,结合
SameSite、双重Cookie等多种策略,可以构建更纵深、更健壮的防护体系。