SpringSecurity实战教程(十二)CORS安全配置 - 跨域请求的安全详解

1253 字
6 分钟
SpringSecurity实战教程(十二)CORS安全配置 - 跨域请求的安全详解

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 项目中,按需灵活地设定跨域安全边界,既满足前后端分离的开发需求,又确保系统不被非授权域滥用。让您的应用将拥有更健壮的跨域防护能力。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
SpringSecurity实战教程(十二)CORS安全配置 - 跨域请求的安全详解
https://fanrich.eu.org/posts/程技/java/springsecurity实战教程/十二cors安全配置---跨域请求的安全详解/
作者
richfan
发布于
2026-03-02
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
richfan
Hello, I'm richfan.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
分类
标签
站点统计
文章
779
分类
8
标签
138
总字数
3,267,679
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录