无法在 Spring 中配置 CSRF 以免面临 CORS 错误

Posted

技术标签:

【中文标题】无法在 Spring 中配置 CSRF 以免面临 CORS 错误【英文标题】:Unable to configure CSRF in Spring not to face CORS error 【发布时间】:2017-11-29 22:19:18 【问题描述】:

按照Spring Boot's Issue #5834,为了设置正确的CORS并解除支持所有来源的错误,我有以下代码:

@Configuration
@EnableWebSecurity
public class SecurityAdapter extends WebSecurityConfigurerAdapter

    @Override
    protected void configure(HttpSecurity http)
        throws Exception
    
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests();

        authorizeRequests.antMatchers("/logon_check").permitAll();
        authorizeRequests.antMatchers("/logon").permitAll();
        authorizeRequests.anyRequest().authenticated();

        http
            .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
            .cors()
        .and()
            .httpBasic()
        .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
    

    @Bean
    public CorsConfigurationSource corsConfigurationSource() 
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    


@Configuration
public class WebConfig extends WebMvcConfigurerAdapter

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        registry.addMapping("/**")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    

但是 OPTIONS 预检请求返回 403:

XMLHttpRequest cannot load http://192.168.2.10:8080/logon_check. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.2.10:4200' is therefore not allowed access. The response had HTTP status code 403.

这些是请求标头:

OPTIONS /logon_check HTTP/1.1
Host: 192.168.2.10:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: GET
Origin: http://192.168.2.10:4200
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/59.0.3071.109 Safari/537.36
Access-Control-Request-Headers: x-requested-with
Accept: */*
Referer: http://192.168.2.10:4200/logon
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,fa;q=0.6

和响应头:

HTTP/1.1 403
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 20
Date: Mon, 26 Jun 2017 23:56:06 GMT

有人可以帮我正确配置 Spring 以便所有来源都通过吗?

【问题讨论】:

【参考方案1】:

我找到了解决问题的方法,但我不确定这种解决方法是否正确。

在跟踪 Spring 的代码几个小时后,我意识到问题出在请求中允许的 HTTP 标头上。所以改变这一行可以解决问题:

configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type", "X-Requested-With", "X-XSRF-TOKEN"));

在上述行中,我已将"X-Requested-With", "X-XSRF-TOKEN" 添加到请求允许拥有的标头列表中。这两个额外的标题是我需要添加的。可能还有一些其他情况/浏览器可能需要其他一些标头。所以一般的解决办法是:

configuration.setAllowedHeaders(ImmutableList.of("*"));

但同样,我不确定这是否存在安全风险。

【讨论】:

以上是关于无法在 Spring 中配置 CSRF 以免面临 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

Springs CSRF 保护 HTML *only* 登录页面

无法使用 Spring Security 创建 CSRF 令牌

CORS与CSRF在Spring Security中的使用

spring security4.2 配置CSRF防御场景

Spring 安全配置无法正常工作

如何通过 XML 配置仅针对特定 URL 模式在 Spring Security 4 中禁用 CSRF?