在这里插入图片描述

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
🌞《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

回顾链接:
最新Spring Security实战教程(一)初识Spring Security安全框架
最新Spring Security实战教程(二)表单登录定制到处理逻辑的深度改造
最新Spring Security实战教程(三)Spring Security 的底层原理解析
最新Spring Security实战教程(四)基于内存的用户认证
最新Spring Security实战教程(五)基于数据库的动态用户认证传统RBAC角色模型实战开发
最新Spring Security实战教程(六)最新Spring Security实战教程(六)基于数据库的ABAC属性权限模型实战开发
最新Spring Security实战教程(七)方法级安全控制@PreAuthorize注解的灵活运用
最新Spring Security实战教程(八)Remember-Me实现原理 - 持久化令牌与安全存储方案
最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合
最新Spring Security实战教程(十)权限表达式进阶 - 在SpEL在安全控制中的高阶魔法
最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践

专栏更新完毕后,博主将会上传所有章节代码到CSDN资源免费给大家下载,如你不想等后续章节代码需提前获取,可以私信或留言!

1. 前言

我们日常开发中,跨域资源共享(CORS)已成为前端与后端分离架构的必备能力。正确配置 CORS 是后端安全边界的重要一环。但安全与便利的天平往往难以把握——过于宽松的配置可能导致敏感数据泄露,过于严格的策略又会影响正常业务交互,本文我们继续Spring Security 实战教程讲解CORS安全配置。


2. 背景与原理概述

跨域请求是指浏览器在一个域(Origin A)加载的脚本访问另一个域(Origin B)的资源。为保护用户数据,浏览器默认禁止跨域访问,除非服务器在响应头中明确允许。CORS 机制通过 Access-Control-Allow-* 系列头部,告诉浏览器何种跨域请求被允许,从而实现安全的跨域通信​。

2.1 预检请求全流程

当发起“简单请求”时(如 GET/POST 且只有简单头部),浏览器会直接带上 Cookie 等凭证;对复杂请求(如 PUT/DELETE、携带自定义头部)则先发起一次 预检(OPTIONS) 请求,确认服务器同意后才发送实际请求。
在这里插入图片描述

2.2 关键响应头说明

Access-Control-Allow-* 响应头主要包括以下几个:

响应头 安全意义 示例值
Access-Control-Allow-Origin 允许的源列表 https://your-domain.com
Access-Control-Allow-Methods 允许的HTTP方法 GET,POST,PUT
Access-Control-Allow-Headers 允许的请求头 Content-Type,Authorization
Access-Control-Max-Age 预检结果缓存时间(秒) 86400

3. Spring MVC 中的 CORS 支持

Spring Framework 自 4.2 起在 MVC 层面引入了对 CORS 的原生支持,可通过全局配置或注解方式开启​

全局配置(WebMvcConfigurer)

@Configuration
public class CorsGlobalConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")  // 应用到所有 /api 路径
                .allowedOrigins("https://your-domain.com") // 允许的源
                .allowedMethods("GET","POST","PUT")  // 允许的方法
                .allowedHeaders("Content-Type","Authorization")
                .exposedHeaders("X-Total-Count")
                .allowCredentials(true)  // 允许携带 Cookie
                .maxAge(3600);   // 预检结果缓存 1 小时
    }
}

注解方式(@CrossOrigin)

@RestController
@RequestMapping("/users")
@CrossOrigin(
    origins = "https://your-domain.com",
    methods = {RequestMethod.GET,RequestMethod.POST},
    allowCredentials = "true",
    maxAge = 1800
)
public class UserController {
    @GetMapping
    public List<User> list() {}
}

4. Spring Security 安全配置方案

尽管 Spring MVC 已处理了 CORS,但如果启用了 Spring Security,必须在 Spring Security 配置中显式开启 CORS 支持,否则安全过滤器会在 MVC 之前拦截预检请求,导致跨域失败

全局安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors
                .configurationSource(corsConfigurationSource())
            )
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated()
            )
            // 其他安全配置...
        return http.build();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("https://your-domain.com"));
        config.setAllowedMethods(List.of("GET", "POST"));
        config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
        config.setExposedHeaders(List.of("X-Custom-Header"));
        config.setMaxAge(3600L);
        config.setAllowCredentials(true);

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

5. 安全强化最佳实践

5.1 动态源配置方案

很多时候我们并不希望相关配置是些死在代码里的,我们可以构建 CorsConfigurationSource 来实现动态源配置方案,这里以读取环境变量举例:

@Bean
CorsConfigurationSource corsConfigurationSource(Environment env) {
    CorsConfiguration config = new CorsConfiguration();
    
    // 从环境变量读取允许的源
    String allowedOrigins = env.getProperty("cors.allowed.origins", "");
    config.setAllowedOrigins(Arrays.asList(allowedOrigins.split(",")));
    
    config.applyPermitDefaultValues();
    config.setAllowCredentials(true);

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

5.2 安全头信息增强

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .cors(withDefaults())
        .headers(headers -> headers
            .httpStrictTransportSecurity(hsts -> hsts
                .includeSubDomains(true)
                .preload(true)
                .maxAgeInSeconds(63072000)
            )
            .xssProtection(xss -> xss
                .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
            )
            .contentSecurityPolicy(csp -> csp
                .policyDirectives("default-src 'self'")
            )
        );
    return http.build();
}

6. 前后端联合调试方案

假设前端部署在 https://frontend.app,后端 API 接口在 https://your-domain.com

  • 后端全局配置(见目录 4. Spring Security 安全配置方案)允许该前端域名。
  • 前端请求示例:
// 带凭证的跨域请求
fetch('https://your-domain.com/data', {
  method: 'GET',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  }
})
.then(response => {
  console.log('Allowed Headers:', 
    response.headers.get('Access-Control-Allow-Headers'));
});

先发起 OPTIONS https://your-domain.com/data,带上 Origin: https://frontend.app

后端返回:

Access-Control-Allow-Origin: https://frontend.app
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Headers: Content-Type,Authorization


7. 常见安全隐患与对策

7.1 风险矩阵

错误配置 潜在风险 解决方案
Access-Control-Allow-Origin: * 敏感数据泄露 动态白名单机制
允许全部HTTP方法 未授权操作风险 最小权限原则
暴露敏感响应头 信息泄露风险 严格控制exposedHeaders
缺失Vary: Origin头 缓存投毒攻击 自动添加Vary头

7.2 生产环境检查清单

  1. 禁用allowedOrigins("*")
  2. 设置合理的maxAge值(建议≤1小时)
  3. 严格限制allowedHeaders范围
  4. 启用allowCredentials时必须指定具体源
  5. 结合CSRF保护关键操作

8. 结语

CORS 配置的本质是在便利性与安全性之间寻找平衡点。通过 Spring Security 的精细化配置,我们可以:

  1. 建立清晰边界:精确控制可交互的客户端范围
  2. 实施最小授权:按需开放必要的HTTP方法和头部
  3. 实现动态防御:根据环境变化自动调整安全策略
  4. 构建纵深防御:与CSRF、CSP等安全机制形成合力
# 生产环境推荐配置示例
cors.allowed.origins=https://web-client.com,https://mobile-client.com
cors.max-age=3600
cors.exposed-headers=X-Request-ID

通过本文内容,相信小伙伴们已经可以在 Spring Boot + Spring Security 项目中,按需灵活地设定跨域安全边界,既满足前后端分离的开发需求,又确保系统不被非授权域滥用。让大家的应用将拥有更健壮的跨域防护能力。

如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!


在这里插入图片描述

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐