Spring cors

今天遇到一个问题,就是spring中配置cors没有效果。原来是因为被spring security拦截处理了。配置了CorsFilter在Spring security过滤器链之后,而通过WebMvcConfigurationSupport配置的CorsConfiguration则是Spring MVC中的, 更是在Spring security过滤器链的后面, 因此没有效果。而通过配置CorsConfigurationSource则会在Spring Security的过滤链中加上CORS过滤器。

Spring security的文档这样说:
Spring中添加CORS配置最简单的方法是通过CorsFilter, 也可以通过配置CorsConfigurationSource来使spring security使用cors, 这样会把CorsFilter加到Spring security的过滤器链中。

我的发现:
在Spring webFlux security中, 如果自己定义CorsFitler, 必须保证在Spring security的过滤器链之前, 这样才不会被Spring Security拦截处理, 从而没有了Cors过滤器。通过指定过滤器的Order为 @Order(Ordered.HIGHEST_PRECEDENCE)会在Spring security的过滤器链之前处理。

而在Spring Web Security 中则可以直接指定CorsFilter, Spring security会直接使用已有的CorsFilter。
https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

Spring Web Flux Cors

看下Spring webflux security是如何把cors加到过滤器链中的:
在http.build()中

  if (this.cors != null) {
    this.cors.configure(this);
  }
protected void configure(ServerHttpSecurity http) {
  CorsWebFilter corsFilter = this.getCorsFilter();
  if (corsFilter != null) {
    http.addFilterAt(this.corsFilter, SecurityWebFiltersOrder.CORS);
  }

}
private CorsWebFilter getCorsFilter() {
  if (this.corsFilter != null) {
    return this.corsFilter;
  } else {
    CorsConfigurationSource source = (CorsConfigurationSource)ServerHttpSecurity.this.getBeanOrNull(CorsConfigurationSource.class);
    if (source == null) {
      return null;
    } else {
      CorsProcessor processor = (CorsProcessor)ServerHttpSecurity.this.getBeanOrNull(CorsProcessor.class);
      if (processor == null) {
        processor = new DefaultCorsProcessor();
      }

      this.corsFilter = new CorsWebFilter(source, (CorsProcessor)processor);
      return this.corsFilter;
    }
  }
}

而通过ServerHttpSecurity.this.getBeanOrNull()方法获取容器中的bean, 从而在这里获取CorsConfigurationSource实例配置CORS。

Spring Web Security Cors

而在spring web security中似乎spring security是可以识别CorsFilter并使用的, 这里没有实际测试过。

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .cors().disable()
        .httpBasic().disable()
        .formLogin().disable()
        .addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class)
        .authorizeRequests()
        .antMatchers("/actuator/**").permitAll()
        .antMatchers(
            "/company/user/check/**",
        ).permitAll()
        .anyRequest().authenticated()
        .and()
        .exceptionHandling().authenticationEntryPoint(defaultAuthenticationEntryPoint);
  }

而在HttpSecurity类中

  public CorsConfigurer<HttpSecurity> cors() throws Exception {
    return (CorsConfigurer)this.getOrApply(new CorsConfigurer());
  }

Spring web security CorsConfigurer中:

  private CorsFilter getCorsFilter(ApplicationContext context) {
    if (this.configurationSource != null) {
      return new CorsFilter(this.configurationSource);
    } else {
      boolean containsCorsFilter = context.containsBeanDefinition("corsFilter");
      if (containsCorsFilter) {
        return (CorsFilter)context.getBean("corsFilter", CorsFilter.class);
      } else {
        boolean containsCorsSource = context.containsBean("corsConfigurationSource");
        if (containsCorsSource) {
          CorsConfigurationSource configurationSource = (CorsConfigurationSource)context.getBean("corsConfigurationSource", CorsConfigurationSource.class);
          return new CorsFilter(configurationSource);
        } else {
          boolean mvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.handler.HandlerMappingIntrospector", context.getClassLoader());
          return mvcPresent ? CorsConfigurer.MvcCorsFilter.getMvcCorsFilter(context) : null;
        }
      }
    }
  }

首先检查CorsFilter, 然后检查CorsConfigurationSource bean。
此时直接设置CorsFilter是可以加到spring security过滤器链中的。

Spring mvc Cors

Spring MVC的文档这样说:
Spring MVC 的HandlerMapping实现内置支持CORS, 在成功映射一个请求到一个handler之后, HandlerMapping会检查CORS配置以采取下一步动作。
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors-processing

我的发现:
Spring MVC会在找到handler后通过添加一个拦截器来检查CORS配置。
Spring MVC的CORS是在找到hander之后, 这个更是在Spring security的过滤器链之后, 从而cors没有效果。

下面来看一下Spring MVC中的CORS的实现。
DispatcherServlet调用AbstractHandlerMapping中的getHandler()方法:

  public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Object handler = this.getHandlerInternal(request);
    if (handler == null) {
      handler = this.getDefaultHandler();
    }

    if (handler == null) {
      return null;
    } else {
      if (handler instanceof String) {
        String handlerName = (String)handler;
        handler = this.obtainApplicationContext().getBean(handlerName);
      }

      HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
      if (this.logger.isTraceEnabled()) {
        this.logger.trace("Mapped to " + handler);
      } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        this.logger.debug("Mapped to " + executionChain.getHandler());
      }

      if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
        CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
        executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
      }

      return executionChain;
    }
  }

自动加上一个cors的拦截器:

  protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request, HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
    if (CorsUtils.isPreFlightRequest(request)) {
      HandlerInterceptor[] interceptors = chain.getInterceptors();
      chain = new HandlerExecutionChain(new AbstractHandlerMapping.PreFlightHandler(config), interceptors);
    } else {
      chain.addInterceptor(new AbstractHandlerMapping.CorsInterceptor(config));
    }

    return chain;
  }
 private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource {
    @Nullable
    private final CorsConfiguration config;

    public CorsInterceptor(@Nullable CorsConfiguration config) {
      this.config = config;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      return AbstractHandlerMapping.this.corsProcessor.processRequest(this.config, request, response);
    }

    @Nullable
    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
      return this.config;
    }
  }

DefaultCorsProcessor

  public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request, HttpServletResponse response) throws IOException {
    if (!CorsUtils.isCorsRequest(request)) {
      return true;
    } else {
      ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response);
      if (this.responseHasCors(serverResponse)) {
        logger.trace("Skip: response already contains \"Access-Control-Allow-Origin\"");
        return true;
      } else {
        ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
        if (WebUtils.isSameOrigin(serverRequest)) {
          logger.trace("Skip: request is from same origin");
          return true;
        } else {
          boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
          if (config == null) {
            if (preFlightRequest) {
              this.rejectRequest(serverResponse);
              return false;
            } else {
              return true;
            }
          } else {
            return this.handleInternal(serverRequest, serverResponse, config, preFlightRequest);
          }
        }
      }
    }
  }

dispatcherServlet中在真正invoke handler之前调用拦截器:
doDispatch方法:

  HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
  String method = request.getMethod();
  boolean isGet = "GET".equals(method);
  if (isGet || "HEAD".equals(method)) {
    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
      return;
    }
  }

  if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
  }

  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  if (asyncManager.isConcurrentHandlingStarted()) {
    return;
  }

从而通过加的cors拦截器阻止请求。

转载于:https://www.cnblogs.com/helloz/p/10961039.html

<think>嗯,用户需要了解Spring框架中CORS漏洞的修复方法和安全配置指南。这个问题很具体,说明用户可能正在处理实际项目中的安全问题。 用户提到的CORS漏洞在引用[1]和[3]都有涉及,特别是引用[3]明确指出了"CORS配置过于宽松"是常见的安全问题来源。用户可能遇到了跨域请求的安全隐患,需要具体的解决方案。 从专业角度看,CORS配置问题确实很常见。很多开发者为了方便调试会开放所有来源的跨域请求,但在生产环境忘记收紧策略,这会导致严重的安全漏洞。需要从漏洞原理、修复方法和最佳实践三个层面来解答。 用户提供的引用材料很有价值,其中引用[3]提到的"纵深防御原则"和"持续监控原则"特别适用于CORS配置。修复这类漏洞的关键是平衡功能和安全,既不能完全禁用CORS影响正常功能,也不能过度开放导致风险。 考虑到用户可能是Java开发人员,应该提供具体的代码示例。Spring Security提供了多种配置方式,包括全局配置和细粒度的@CrossOrigin注解。需要特别强调origin白名单的重要性,以及避免使用通配符的安全风险。 用户可能还需要知道如何验证配置是否生效,所以应该包含测试方法。另外,引用[4]提到的依赖库漏洞也值得注意,需要提醒用户保持Spring版本更新,因为旧版本可能存在CORS相关的安全缺陷。 这个问题涉及多个技术点:浏览器同源策略、Spring Security配置、HTTP响应头验证等。回答要分层说明,从漏洞原理到解决方案再到最佳实践,让用户能循序渐进地理解。</think>以下是关于Spring框架中CORS漏洞的修复方法及安全配置指南,结合行业最佳实践和漏洞防护原则: --- ### **一、CORS漏洞风险** 宽松的CORS配置会导致: 1. **跨域数据泄露**:恶意网站可读取敏感数据 2. **CSRF攻击增强**:攻击者利用信任域执行未授权操作 3. **权限绕过**:未验证的Origin头可能绕过访问控制 > 引用[1]指出:*"CORS配置过于宽松"* 是Spring安全配置的常见漏洞来源[^1] --- ### **二、修复方案与安全配置** #### **1. 精确配置Origin白名单** ```java @Configuration @EnableWebMvc public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("https://trusted-domain.com", "https://app.example.com") // 精确域名 .allowedMethods("GET", "POST") .allowCredentials(true) .maxAge(3600) .exposedHeaders("Authorization"); } } ``` **关键参数**: - `allowedOrigins()`:**禁止使用`*`通配符**,仅配置受信任域名 - `allowCredentials(true)`:需与具体域名配合,否则浏览器会拒绝 - `exposedHeaders()`:显式声明暴露的敏感头(如Authorization) #### **2. Spring Security分层防护** ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf().disable(); // 根据场景谨慎关闭CSRF } CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("https://trusted-domain.com")); config.setAllowedMethods(Arrays.asList("GET","POST")); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } } ``` #### **3. 防御性响应头控制** 在`application.properties`中强制安全策略: ```properties # 阻止未定义Origin的请求 cors.allow-credentials=true cors.allowed-origins=https://trusted-domain.com # 添加安全响应头 security.headers.content-security-policy=default-src 'self' ``` --- ### **三、高危配置禁止项** | **错误配置** | **风险** | **正确做法** | |----------------------|--------------------------|--------------------------| | `allowedOrigins("*")` | 允许任意域访问 | 精确域名白名单 | | `allowedMethods("*")` | 开放高风险HTTP方法(PUT/DELETE)| 按需开放基础方法(GET/POST)| | 缺失`allowCredentials`| 浏览器可能拒绝合法请求 | 需与`allowedOrigins`配合 | > 引用[3]强调:*"输入不可信原则:所有外部输入都视为潜在威胁"*[^3] --- ### **四、验证与测试方法** 1. **渗透测试**: ```bash curl -H "Origin: http://malicious.com" -I https://your-api.com/data ``` 检查响应头中是否包含`Access-Control-Allow-Origin: http://malicious.com` 2. **自动化扫描**: - 使用OWASP ZAP进行CORS策略扫描 - 集成Trivy检查配置漏洞(引用[3]推荐)[^3] 3. **单元测试**: ```java @Test void testCorsHeaders() { mockMvc.perform(get("/api/data").header("Origin", "https://attacker.com")) .andExpect(header().doesNotExist("Access-Control-Allow-Origin")); } ``` --- ### **五、纵深防御措施** 1. **网络层**:WAF配置CORS规则过滤非法Origin 2. **应用层**: - 使用`@CrossOrigin(origins = "domain")`注解细化到控制器 - 实现`CorsFilter`动态验证Origin(如查询数据库域名白名单) 3. **监控层**: ```java @Component public class CorsMonitor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String origin = request.getHeader("Origin"); log.info("CORS request from origin: {}", origin); // 审计日志 } } ``` > 引用[3]的纵深防御原则:*"网络层+应用层+数据层多重防护"*[^3] --- ### **六、版本安全建议** 1. 升级至Spring Security 5.7+(修复CVE-2022-22978等CORS相关漏洞) 2. 定期检查依赖库: ```bash mvn dependency:tree | grep 'spring-security' ``` 3. 参考[4]:*"如果您没有及修复或升级底层框架,会使组织暴露于固定漏洞的风险中"*[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值