拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Spring CORS Filter实现与跨域安全实践

1. 理解跨域问题的本质在Web开发中跨域问题就像两个不同国家之间的海关检查。想象一下你在中国大陆的网站上点击一个按钮这个按钮要向香港的服务器发送请求获取数据。虽然都是中国的领土但浏览器会认为这是跨国操作需要特殊的安全检查。浏览器实施同源策略(Same-Origin Policy)的根本原因是为了防止恶意网站窃取用户数据。这个策略要求只有当协议(http/https)、域名和端口都完全一致时才允许自由通信。三者中有任何一个不同就被视为跨域请求。2. CORS机制的工作原理CORS(Cross-Origin Resource Sharing)是现代浏览器支持的标准机制它允许服务器声明哪些外部源可以访问自己的资源。这就像海关的绿色通道 - 服务器明确告诉浏览器这些来源的请求可以放行。一个完整的CORS请求流程包含以下几个关键步骤简单请求直接发送实际请求浏览器自动添加Origin头预检请求对于可能修改数据的复杂请求(POST/PUT/DELETE等)浏览器先发送OPTIONS请求服务器响应服务器返回适当的CORS头(Access-Control-Allow-*系列)实际请求通过预检后浏览器发送实际请求3. Spring中实现CORS的Filter方案3.1 为什么选择Filter方案在Spring生态中实现CORS有多种方式但Filter方案具有以下优势处理时机最早Filter是Servlet容器层面的组件能在请求最早阶段处理跨域性能最优避免了Spring MVC层的额外处理开销适用范围广不仅适用于Spring MVC也适用于WebFlux等其他Web框架配置灵活可以精细控制每个请求的跨域行为3.2 核心实现代码解析下面是一个完整的CORS Filter实现示例import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; Component Order(Ordered.HIGHEST_PRECEDENCE) public class CorsFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response (HttpServletResponse) res; HttpServletRequest request (HttpServletRequest) req; // 允许的源生产环境应替换为具体域名 response.setHeader(Access-Control-Allow-Origin, *); // 允许的HTTP方法 response.setHeader(Access-Control-Allow-Methods, POST, GET, OPTIONS, DELETE, PUT, PATCH); // 预检请求缓存时间(秒) response.setHeader(Access-Control-Max-Age, 3600); // 允许的请求头 response.setHeader(Access-Control-Allow-Headers, x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN); // 是否允许携带凭证(cookie等) response.setHeader(Access-Control-Allow-Credentials, true); // 暴露给前端JS能获取的响应头 response.setHeader(Access-Control-Expose-Headers, Authorization, Content-Disposition); if (OPTIONS.equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } Override public void init(FilterConfig filterConfig) { // 初始化逻辑(可选) } Override public void destroy() { // 销毁逻辑(可选) } }3.3 关键配置项详解Access-Control-Allow-Origin最重要的头信息指定允许访问资源的域。生产环境强烈建议替换通配符*为具体的可信域名列表。Access-Control-Allow-Methods定义允许的HTTP方法如GET、POST等。注意要包含OPTIONS方法用于预检。Access-Control-Allow-Headers列出允许的自定义请求头特别是认证相关的头如Authorization。Access-Control-Allow-Credentials当需要传输cookie等凭证信息时必须设置为true且不能使用通配符*作为Origin。Access-Control-Expose-Headers指定哪些响应头可以被前端JavaScript代码访问。4. 生产环境最佳实践4.1 安全配置建议避免使用通配符*在生产环境中应该明确指定允许的域名String allowedOrigins https://yourdomain.com,https://api.yourdomain.com; response.setHeader(Access-Control-Allow-Origin, allowedOrigins);限制HTTP方法只开放必要的HTTP方法减少攻击面response.setHeader(Access-Control-Allow-Methods, GET, POST, OPTIONS);启用CSRF保护当允许凭证时必须配合CSRF防护机制response.setHeader(Access-Control-Allow-Headers, X-Requested-With, X-XSRF-TOKEN);4.2 性能优化技巧合理设置Max-Age预检请求结果可以被浏览器缓存减少OPTIONS请求// 缓存1小时 response.setHeader(Access-Control-Max-Age, 3600);动态Origin检测实现动态Origin白名单兼顾安全与灵活性String origin request.getHeader(Origin); if (isAllowedOrigin(origin)) { response.setHeader(Access-Control-Allow-Origin, origin); }避免重复处理添加条件判断避免对同一请求多次处理CORS头if (!response.containsHeader(Access-Control-Allow-Origin)) { // 添加CORS头 }5. 常见问题排查指南5.1 预检请求失败现象浏览器控制台报错Response to preflight request doesnt pass access control check解决方案确保OPTIONS请求返回200状态码检查Access-Control-Allow-Headers是否包含请求中使用的所有自定义头验证Access-Control-Allow-Methods是否包含请求方法5.2 凭证(Cookie)无法传递现象设置了withCredentialstrue但cookie未随请求发送解决方案确认Access-Control-Allow-Credentials设置为true确保Access-Control-Allow-Origin不是通配符*而是具体域名检查Cookie的SameSite属性设置5.3 响应头不可见现象前端无法通过getResponseHeader()获取自定义头解决方案在服务器端通过Access-Control-Expose-Headers暴露需要的头确保头名称拼写正确区分大小写6. 与其他Spring跨域方案的对比6.1 CrossOrigin注解适合方法级别的细粒度控制但有以下局限只对注解的方法/类生效无法处理非Spring管理的端点配置分散维护成本高6.2 WebMvcConfigurer全局配置方式示例Configuration public class WebConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(https://yourdomain.com) .allowedMethods(GET, POST); } }优缺点配置集中易于管理但仅适用于Spring MVC场景处理时机晚于Filter6.3 响应头手动设置在控制器方法中直接操作HttpServletResponseGetMapping(/data) public ResponseEntity? getData(HttpServletResponse response) { response.setHeader(Access-Control-Allow-Origin, *); // ... }适用场景需要动态控制跨域的特定情况不推荐作为主要方案维护困难7. 高级应用场景7.1 微服务架构中的CORS在Spring Cloud微服务体系中通常有两种方案网关层统一处理在API Gateway(如Spring Cloud Gateway)配置全局CORS简化各服务配置服务各自处理每个服务维护自己的CORS策略灵活性更高但管理复杂7.2 WebSocket跨域WebSocket连接同样受同源策略限制需要在建立连接时处理Configuration public class WebSocketConfig implements WebSocketConfigurer { Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), /ws) .setAllowedOrigins(https://yourdomain.com); } }7.3 文件上传跨域处理文件上传时需要特别注意确保multipart/form-data请求能被预检可能需要额外暴露Content-Disposition头以下载文件8. 测试与验证方法8.1 使用CURL测试验证CORS头是否正确的简单命令curl -H Origin: http://example.com \ -H Access-Control-Request-Method: POST \ -H Access-Control-Request-Headers: X-Requested-With \ -X OPTIONS --verbose http://yourserver.com/api8.2 Postman测试技巧虽然Postman不受同源策略限制但可以手动添加Origin头模拟跨域请求检查响应头中是否包含CORS相关头特别测试OPTIONS预检请求8.3 浏览器端验证前端开发者可以检查网络请求中是否自动添加了Origin头预检请求和实际请求的流程是否符合预期控制台是否有CORS相关错误9. 安全防护补充9.1 CSRF与CORS的协同当启用CORS且允许凭证时必须实施CSRF防护使用Spring Security的CSRF保护配合自定义的XSRF-TOKEN头确保CORS配置允许必要的安全头9.2 速率限制对OPTIONS请求也应实施速率限制防止DDoS攻击if (OPTIONS.equals(request.getMethod())) { rateLimiter.tryAcquire(); }9.3 日志监控记录异常的CORS请求有助于发现攻击尝试String origin request.getHeader(Origin); if (!isAllowedOrigin(origin)) { log.warn(Blocked CORS request from origin: {}, origin); }10. 实际项目中的经验总结在大型电商平台项目中我们采用以下CORS策略分层配置网关层基础CORS设置允许常见HTTP方法业务服务细粒度控制如支付服务只允许POST动态白名单从数据库读取允许的域名列表支持热更新监控告警对异常的Origin来源触发安全告警性能优化对静态资源设置更长的Max-Age缓存时间特别提醒在Spring Boot 2.4版本中如果同时使用了Spring Security需要注意其CORS配置会覆盖自定义Filter的设置。此时需要在Security配置中明确指定CORS来源EnableWebSecurity public class SecurityConfig { Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.cors(cors - cors.configurationSource(request - { CorsConfiguration config new CorsConfiguration(); config.setAllowedOrigins(List.of(https://yourdomain.com)); config.setAllowedMethods(List.of(GET,POST)); return config; })); return http.build(); } }对于非Spring Boot的传统Spring MVC项目需要在web.xml中配置Filterfilter filter-namecorsFilter/filter-name filter-classcom.yourpackage.CorsFilter/filter-class /filter filter-mapping filter-namecorsFilter/filter-name url-pattern/*/url-pattern /filter-mapping最后关于浏览器兼容性需要注意虽然现代浏览器都支持CORS但某些旧版本(如IE9)对CORS的支持有限。如果必须支持这些浏览器可能需要考虑JSONP等备选方案但这已超出本文讨论范围。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门