跨站请求伪造攻击中,攻击者会利用用户已登录的身份,诱导用户访问恶意页面触发非预期请求,比如修改密码、转账等操作。要防御这类攻击,CSRF Token验证是最成熟可靠的方案之一,核心思路是让每个合法请求都携带服务端颁发的唯一随机令牌,服务端校验令牌合法性后再处理请求。

CSRF Token的工作原理
CSRF Token的本质是一个随机生成的字符串,由服务端在用户会话建立时生成,与用户会话绑定。合法请求发起时,令牌会随请求参数或请求头传递到服务端,服务端对比请求中的令牌和会话中存储的令牌是否一致,一致则认为是合法请求,否则拒绝处理。
攻击者无法获取目标用户的CSRF Token,因此无法构造出包含合法令牌的恶意请求,也就无法完成跨站请求伪造攻击。
后端实现CSRF Token验证
1. 生成与存储CSRF Token
用户登录成功后,服务端生成随机CSRF Token,存储到用户的会话中,同时将令牌返回给前端。以下是Java Spring Boot框架的生成示例:
import java.util.UUID;
import javax.servlet.http.HttpSession;
public class CsrfTokenUtil {
// 生成CSRF Token并存入会话
public static String generateToken(HttpSession session) {
String token = UUID.randomUUID().toString().replace("-", "");
// 将会话中存储的令牌键设为csrf_token
session.setAttribute("csrf_token", token);
return token;
}
}
2. 校验CSRF Token
服务端在处理敏感请求时,从请求参数或请求头中获取令牌,和会话中存储的令牌对比。以下是校验逻辑的示例:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class CsrfTokenUtil {
// 校验CSRF Token合法性
public static boolean validateToken(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
// 从请求头中获取令牌,也可以从请求参数获取
String requestToken = request.getHeader("X-CSRF-TOKEN");
if (requestToken == null) {
requestToken = request.getParameter("csrf_token");
}
String sessionToken = (String) session.getAttribute("csrf_token");
// 令牌为空或者不匹配则返回false
if (sessionToken == null || !sessionToken.equals(requestToken)) {
return false;
}
return true;
}
}
3. 拦截器配置
可以通过拦截器统一处理所有需要校验的请求,避免在每个接口中重复编写校验逻辑。以下是Spring Boot拦截器的配置示例:
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CsrfInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 放行GET等非修改请求,只校验POST、PUT、DELETE等修改请求
String method = request.getMethod();
if ("GET".equalsIgnoreCase(method) || "HEAD".equalsIgnoreCase(method) || "OPTIONS".equalsIgnoreCase(method)) {
return true;
}
boolean isValid = CsrfTokenUtil.validateToken(request);
if (!isValid) {
response.setStatus(403);
response.getWriter().write("CSRF Token验证失败");
return false;
}
return true;
}
}
前端传递CSRF Token
1. 表单请求传递
如果是表单提交,可以在表单中隐藏一个input标签存放CSRF Token,提交时随表单数据一起传递:
<form action="/update-password" method="post">
<!-- 隐藏的CSRF Token字段 -->
<input type="hidden" name="csrf_token" value="${csrfToken}">
<input type="password" name="newPassword" placeholder="请输入新密码">
<button type="submit">修改密码</button>
</form>
2. Ajax请求传递
如果是Ajax请求,可以将CSRF Token放到请求头中传递,以下是原生JavaScript的示例:
// 假设从页面元标签中获取CSRF Token
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({
amount: 100,
targetAccount: '123456'
})
})
.then(response => {
if (response.ok) {
console.log('请求处理成功');
} else {
console.log('请求处理失败');
}
});
实现注意事项
- CSRF Token必须是随机生成的高熵值字符串,避免使用可预测的序列,防止被攻击者猜测。
- Token要和用户的会话绑定,不同用户的Token不能通用,用户退出登录后要清除会话中的Token。
- 敏感操作对应的Token可以设置一次性使用,使用后立即失效并生成新的Token,进一步提升安全性。
- 不要在Cookie中直接存储CSRF Token,避免被攻击者通过XSS攻击获取,建议存储在服务端会话或者前端的不可被脚本随意读取的存储位置。
- 对于文件上传等包含特殊Content-Type的请求,要确保Token能够正确传递,避免因为请求格式问题导致校验失败。
CSRF Token验证是防御跨站请求伪造的基础方案,结合同源策略、Cookie的SameSite属性等防护措施,可以构建更完善的Web安全防护体系。
CSRF_Token跨站请求伪造Web安全Token验证修改时间:2026-06-27 20:54:56