CSRF 跨站请求伪造
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种利用用户已登录的身份,在用户不知情的情况下执行非授权操作的攻击方式。本章将详细介绍 CSRF 的原理和防护方法。
什么是 CSRF?
CSRF 攻击利用了 Web 应用的身份验证机制。当用户登录某个网站后,浏览器会保存该网站的会话 Cookie。攻击者可以诱导用户访问一个恶意页面,该页面会自动向目标网站发送请求,利用用户的登录状态完成非法操作。
CSRF 攻击原理
攻击流程
1. 用户登录网站 A(如银行网站)
2. 浏览器保存会话 Cookie
3. 用户访问攻击者控制的网站 B
4. 网站 B 包含向网站 A 发送请求的代码
5. 浏览器自动携带网站 A 的 Cookie
6. 网站 A 认为请求来自合法用户,执行操作
攻击示例
假设银行网站的转账接口:
<!-- 银行转账表单 -->
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to" value="attacker-account">
<input type="hidden" name="amount" value="10000">
</form>
攻击者可以构造恶意页面:
<!-- 恶意页面 -->
<html>
<body>
<h1>点击这里赢取大奖!</h1>
<!-- 隐藏的表单,自动提交 -->
<form action="https://bank.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="to" value="attacker-account">
<input type="hidden" name="amount" value="10000">
</form>
<script>
document.getElementById('csrf-form').submit();
</script>
</body>
</html>
当已登录的用户访问这个页面时,转账请求会自动发送。
CSRF 的危害
CSRF 攻击可以导致:
- 资金转移 - 从银行账户转账
- 数据修改 - 更改用户设置、邮箱等
- 权限提升 - 添加管理员账户
- 删除数据 - 删除重要信息
- 发布内容 - 发布恶意信息
CSRF 防护
1. CSRF Token
最常用的防护方法是使用 CSRF Token:
// 生成 CSRF Token
String csrfToken = UUID.randomUUID().toString();
session.setAttribute("csrf_token", csrfToken);
// 在表单中添加隐藏字段
<input type="hidden" name="_csrf" value="${csrfToken}" />
// 验证 Token
String requestToken = request.getParameter("_csrf");
String sessionToken = (String) session.getAttribute("csrf_token");
if (!csrfToken.equals(requestToken)) {
throw new SecurityException("CSRF 攻击检测");
}
2. Spring Security CSRF 防护
Spring Security 默认启用 CSRF 防护:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf() // 默认启用
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
// ...
}
}
3. 验证请求头
检查请求的来源:
// 验证 Referer 和 Origin 头
String origin = request.getHeader("Origin");
String referer = request.getHeader("Referer");
if (origin != null && !isTrustedOrigin(origin)) {
throw new SecurityException("不信任的来源");
}
4. SameSite Cookie
使用 SameSite 属性防止 CSRF:
Cookie cookie = new Cookie("SESSION_ID", sessionId);
cookie.setSameSite("Strict"); // 最严格
// 或
cookie.setSameSite("Lax"); // 较宽松,但更实用
response.addCookie(cookie);
SameSite 有三个值:
- Strict:完全阻止跨站请求
- Lax:允许部分跨站请求(如链接)
- None:不限制(需要 Secure=true)
5. 双重提交 Cookie
将 Token 同时放在 Cookie 和请求参数中:
// 设置 Cookie
document.cookie = "csrf-token=" + token + "; path=/";
// 请求时同时发送
fetch('/api/data', {
method: 'POST',
headers: {
'X-CSRF-Token': getCookie('csrf-token')
}
});
检测 CSRF 漏洞
手动测试
- 登录应用
- 记录关键操作(如修改密码、转账)
- 构造恶意页面,尝试触发相同操作
- 检查是否成功执行
自动化工具
- OWASP ZAP:自动检测 CSRF 漏洞
- Burp Suite:CSRF 检测功能
最佳实践
- 启用 CSRF 防护 - 始终使用 CSRF Token
- 使用 SameSite Cookie - 为会话 Cookie 设置 SameSite
- 验证请求来源 - 检查 Origin 和 Referer
- 敏感操作验证 - 重要操作需要额外确认
- 避免使用 GET 修改数据 - 使用 POST/PUT 进行状态修改
小结
CSRF 攻击利用用户的登录状态,在用户不知情的情况下执行非授权操作:
-
攻击原理
- 诱导用户访问恶意页面
- 自动发送携带认证 Cookie 的请求
- 服务器无法区分是否为用户主动操作
-
防护措施
- CSRF Token(最有效)
- SameSite Cookie
- 验证请求来源
- 双重提交验证
-
最佳实践
- 始终启用 CSRF 防护
- 使用框架自带的安全功能
- 敏感操作增加额外验证