什么是 CSRF?
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种利用用户已登录身份,诱导其在不知情的情况下向受信任网站发送恶意请求的攻击方式。攻击者通过构造特定的请求,借助用户的浏览器自动携带的认证信息(如 Cookie),使服务器误以为是用户的合法操作,从而执行非授权的敏感操作。
攻击原理

CSRF 攻击的核心在于:
- 身份伪造:攻击者无法直接获取用户的认证信息,但可以诱导用户的浏览器发送携带认证信息的请求。
- 跨站请求:攻击者在其控制的站点上嵌入指向受信任站点的请求,当用户访问攻击者站点时,浏览器会自动发送这些请求。
- 服务器信任:服务器根据请求中的认证信息(如 Cookie)判断请求的合法性,而不验证请求的来源,从而执行了攻击者构造的操作。
攻击流程
- 用户登录受信任网站(如 bank.com),浏览器保存了会话 Cookie。
- 用户在未登出 bank.com 的情况下,访问了攻击者控制的恶意网站。
- 恶意网站向 bank.com 发送伪造请求(如转账),浏览器自动附带 Cookie。
- bank.com 接收到请求,验证 Cookie 合法,执行了转账操作。
真实案例分析
WordPress CSRF 漏洞(2012)
攻击者利用 WordPress 3.3.1 版本中的 CSRF 漏洞,诱导管理员用户点击恶意链接,从而添加具有管理员权限的用户,篡改站点设置。美团技术
YouTube CSRF 漏洞(2008)
攻击者通过构造特定的请求,使用户在不知情的情况下将视频添加到“Favorites”,甚至发送消息、添加好友,导致用户隐私泄露和内容操控。美团技术
防御策略
1. 使用 CSRF Token(同步令牌)
在每次表单提交时,服务器生成一个唯一的 CSRF Token,并将其嵌入到表单中。服务器在接收到请求时,验证 Token 的有效性,确保请求来源合法。
实现示例(PHP):
// 生成 CSRF Token
function generate_csrf_token() {
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
return $token;
}
// 验证 CSRF Token
function verify_csrf_token($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
攻击者无法获取有效的 Token,从而防止 CSRF 攻击。
2. 设置 SameSite Cookie 属性
通过设置 Cookie 的 SameSite 属性,限制浏览器在跨站请求中发送 Cookie,从而降低 CSRF 风险。
Strict
:Cookie 仅在同站请求中发送,最严格的设置。Lax
:Cookie 在大多数跨站请求中不会被发送,但在用户导航到目标网站的跨站请求中发送。None
:Cookie 在所有请求中发送,包括跨站请求。必须设置 Secure 属性。
设置示例(HTTP Header):
Set-Cookie: sessionid=abc123; SameSite=Strict; Secure; HttpOnly
现代浏览器已广泛支持 SameSite 属性,推荐结合使用 Secure
和 HttpOnly
属性,增强 Cookie 的安全性。
3. 验证 Referer 或 Origin 头
服务器在处理敏感请求时,检查请求头中的 Referer 或 Origin 字段,确保请求来源于受信任的域名。
注意事项:
- Referer 头可能被用户禁用或伪造,不应作为唯一的防护手段。
- Origin 头在跨站请求中更可靠,推荐优先使用。
4. 双重提交 Cookie
在 Cookie 和请求参数中同时发送相同的 Token,服务器验证两者是否一致。攻击者无法同时伪造 Cookie 和请求参数,从而防止 CSRF 攻击。
实现步骤:
- 服务器在响应中设置一个 Cookie,包含 CSRF Token。
- 客户端在发送请求时,将该 Token 作为请求参数或自定义头部发送。
- 服务器验证请求中的 Token 与 Cookie 中的 Token 是否一致。
5. 使用验证码或双重认证(2FA)
对于敏感操作,要求用户输入验证码或进行双重认证(如短信验证码、硬件令牌),增加攻击难度。
优点:
- 即使攻击者伪造了请求,也无法通过额外的验证步骤。
缺点:
- 增加用户操作步骤,可能影响用户体验。
6. 限制请求方法
对于修改操作,使用 POST、PUT、DELETE 等请求方法,避免使用 GET 方法。攻击者难以在第三方网站中构造非 GET 请求,从而降低 CSRF 风险。
实现建议:
- 在服务器端配置中,禁止对敏感操作使用 GET 请求。
- 在前端开发中,确保表单和 AJAX 请求使用正确的 HTTP 方法。