Skip to content

Spring Security CSRF 与 CORS

CSRF 和 CORS 经常被混在一起。CSRF 是防止用户在已登录状态下被第三方网站诱导发起危险请求;CORS 是浏览器限制跨域读取响应的安全策略。

区别

项目CSRFCORS
解决问题防止跨站请求伪造控制浏览器跨域访问
发生位置服务端校验请求可信度浏览器和服务端协商
常见场景Cookie Session 登录前后端分离跨域调用
配置结果拒绝缺少 CSRF Token 的请求返回跨域响应头

CORS 预检流程

mermaid
sequenceDiagram
    participant B as 浏览器
    participant S as 服务端
    B->>S: OPTIONS 预检请求
    S-->>B: Access-Control-Allow-Origin 等响应头
    B->>S: 真实业务请求
    S-->>B: 业务响应

CSRF 校验流程

mermaid
flowchart TD
    A[危险请求] --> B{是否需要CSRF保护}
    B -- 否 --> C[继续过滤器链]
    B -- 是 --> D{Token是否匹配}
    D -- 是 --> C
    D -- 否 --> E[拒绝请求]

配置建议

  1. 传统 Session + Cookie 登录,建议开启 CSRF。
  2. 纯 Token 鉴权且 Token 放在 Authorization 请求头中,通常可以关闭 CSRF。
  3. CORS 不要简单配置 * 加凭证,带 Cookie 时必须指定明确 Origin。
  4. 预检请求要允许 OPTIONS,否则浏览器会在真实请求前失败。
  5. 网关层和应用层不要重复写冲突的跨域响应头。

排查顺序

跨域问题先看浏览器控制台,再看响应头。401/403 是鉴权问题,CORS 报错是浏览器拦截问题,两者处理方向不同。

配置 Demo:前后端分离 CORS

java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .cors(Customizer.withDefaults())
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/admin/login").permitAll()
            .anyRequest().authenticated()
        );
    return http.build();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("http://localhost:5173"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
    config.setAllowCredentials(true);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

如果 Token 放在 Authorization 请求头里,通常可以关闭 CSRF;如果使用 Cookie Session 登录,则要重新评估 CSRF 防护。