SpringBoot + Sa-Token 实现 CSRF 令牌校验(进阶篇)

前言

在上一篇中,我们通过 CORS 配置和 Origin/Referer 校验,搭建了基础的浏览器安全防护。但这些手段无法防御同源下的 CSRF 攻击,也无法完全避免工具伪造请求。本文将结合 Sa-Token 自带的 SaCsrfUtil,实现随机、单次有效的 CSRF 令牌校验,完成安全防护的最后一环。


一、CSRF 令牌的核心原理

CSRF 令牌的防御逻辑非常简单:

  1. 用户登录后,服务器生成一个随机、一次性有效的 CSRF 令牌,返回给前端。
  2. 前端在发起敏感请求(POST/PUT/DELETE)时,必须携带这个令牌。
  3. 服务器校验令牌的有效性,校验通过后立即作废,确保令牌无法复用。

二、Sa-Token CSRF 令牌的使用

1. 生成并返回 CSRF 令牌

在用户登录或页面加载时,生成令牌并返回给前端:

java

运行

kotlin 复制代码
import cn.dev33.satoken.csrf.SaCsrfUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/auth")
public class AuthController {

    // 生成一次性 CSRF 令牌
    @GetMapping("/csrf-token")
    public String getCsrfToken() {
        return SaCsrfUtil.createToken();
    }
}

2. 在 Sa-Token 拦截器中校验令牌

在之前的拦截器中,添加敏感请求的 CSRF 令牌校验逻辑:

java

运行

less 复制代码
@Slf4j
@Configuration
public class SaTokenSecurityConfig {

    @Value("${spring.profiles.active:dev}")
    private String activeProfile;

    @Value("#{'${system.cors.origin_url:}'.split(',')}")
    private List<String> allowedOrigins;

    @Bean
    public SaInterceptor saInterceptor() {
        return new SaInterceptor(handler -> {
            // 1. 基础登录校验
            StpUtil.checkLogin();

            // 2. 开发环境 Origin/Referer 校验
            if (!Arrays.asList("test", "stg", "prod").contains(activeProfile)) {
                // 校验逻辑同上一篇,此处省略
            }

            // 3. 敏感请求 CSRF 令牌校验
            String method = handler.getRequest().getMethod();
            if (Arrays.asList("POST", "PUT", "DELETE").contains(method)) {
                SaCsrfUtil.checkToken();
            }
        });
    }
}

三、前端如何携带 CSRF 令牌?

前端在发起敏感请求时,需要将令牌放入请求头中,Sa-Token 默认会从 X-CSRF-Token 头中读取令牌:

javascript

运行

javascript 复制代码
// 1. 页面加载时获取令牌
let csrfToken = "";
fetch("/auth/csrf-token")
  .then(res => res.text())
  .then(token => {
    csrfToken = token;
  });

// 2. 发起敏感请求时携带令牌
fetch("/api/user/update", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${localStorage.getItem('token')}`,
    "X-CSRF-Token": csrfToken,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ name: "新名字" })
});

四、完整防护闭环:四种手段协同工作

现在我们已经实现了全部四种浏览器安全防护手段,它们各司其职,形成了完整的防护闭环:

表格

防护手段 作用 防御场景
SameSite/HttpOnly/Secure Cookie 让浏览器不跨站携带 Cookie,且防止 JS 读取 跨站 CSRF、XSS 窃取 Cookie
CORS 跨域配置 让浏览器主动拒绝非白名单跨域请求 浏览器发起的跨域请求
Origin/Referer 校验 服务器端校验请求来源,拒绝非法域名 工具伪造请求、绕过 CORS 的请求
CSRF 令牌校验 敏感请求必须携带一次性有效令牌 同源 CSRF 攻击、工具重放请求

五、生产环境部署注意事项

  1. 强制 HTTPS :所有环境必须使用 HTTPS,否则 secure: true 配置会导致 Cookie 无法携带。
  2. 令牌过期时间:可根据业务场景调整 CSRF 令牌的有效期,避免影响用户体验。
  3. 日志监控:对 Origin/Referer 校验失败、CSRF 令牌校验失败的请求,添加日志监控,及时发现异常攻击行为。
  4. 避免通配符配置 :生产环境严禁使用 * 作为跨域允许的 Origin,必须配置明确的白名单。

结语

浏览器安全防护不是靠某一种手段就能实现的,而是多种手段协同工作的结果。通过 Sa-Token 框架,我们可以快速实现 CORS、Origin/Referer 校验、Cookie 安全属性和 CSRF 令牌校验,为项目搭建起坚固的安全防线。希望本文能帮你解决跨域与 CSRF 防护的痛点,写出更安全的前后端分离项目代码。

相关推荐
aibo8603083 分钟前
基于 Spring Boot + Vue3 的菜谱分享网站设计与实现
java·spring boot·后端
凤山老林4 分钟前
Spring Boot 集成 TOTP 双因素认证与恢复码机制
java·spring boot·后端
vipxieliang5 分钟前
ThinkPHP MVC 模式入门:从控制器到视图的完整实践
后端·php·thinkphp
vipxieliang11 分钟前
Spring Boot 测试策略:单元测试、切片测试与集成测试
java·spring boot·后端
vipxieliang12 分钟前
Go 1.24 工具链改进实战:工具依赖管理与 go vet 新分析器
后端·go
掘金者阿豪12 分钟前
慢 SQL 优化别急着加索引:从订单分页查询聊聊 KES 执行计划
后端
涡能增压发动积13 分钟前
AI 对一位老开发的副作用总结
后端
未秃头的程序猿23 分钟前
同一个商户号,V2 免密代扣和 V3 分账的证书怎么共存?
java·后端·微信
众乐乐_200829 分钟前
【实操解决】PHP5.4~PHP7.3的 CVE-2026-109618与CVE-2026-109619问题
安全·php
captain37637 分钟前
Spring Boot的配置文件
java·spring boot·后端