복붙노트

[SPRING] 봄 부팅 보안 CORS

SPRING

봄 부팅 보안 CORS

스프링 보안 URL에 CORS 필터 문제가 있습니다. Springsec (로그인 / 로그 아웃)에 속하거나 URL 보안에 의해 필터링 된 URL에 Access-Control-Allow-Origin 및 기타 노출 된 헤더를 설정하지 않습니다.

다음은 구성입니다.

코스 :

@Configuration
@EnableWebMvc
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
********some irrelevant configs************
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/*").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT")
                .allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
                        "Access-Control-Request-Headers")
                .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
                .allowCredentials(true).maxAge(3600);
    }
}

보안:

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                .formLogin()
                    .successHandler(ajaxSuccessHandler)
                    .failureHandler(ajaxFailureHandler)
                    .loginProcessingUrl("/authentication")
                    .passwordParameter("password")
                    .usernameParameter("username")
                .and()
                .logout()
                    .deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true)
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                .and()
                .csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers("/authentication").permitAll()
                .antMatchers("/oauth/token").permitAll()
                .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
                .antMatchers("/user/*").access("hasRole('ROLE_USER')");
    }
}

그래서, 보안에 귀를 기울이지 않은 URL을 요청하면 CORS 헤더가 설정됩니다. 봄 보안 URL - 설정되지 않았습니다.

봄 부팅 1.4.1

해결법

  1. ==============================

    1.CorsRegistry를 사용하는 대신 자신의 CorsFilter를 작성하여 보안 구성에 추가 할 수 있습니다.

    CorsRegistry를 사용하는 대신 자신의 CorsFilter를 작성하여 보안 구성에 추가 할 수 있습니다.

    사용자 정의 CorsFilter 클래스 :

    public class CorsFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            HttpServletRequest request= (HttpServletRequest) servletRequest;
    
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "*");
            response.setHeader("Access-Control-Allow-Credentials", true);
            response.setHeader("Access-Control-Max-Age", 180);
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    보안 구성 클래스 :

    @Configuration
    @EnableWebSecurity
    public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Bean
        CorsFilter corsFilter() {
            CorsFilter filter = new CorsFilter();
            return filter;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
                    .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                    .formLogin()
                        .successHandler(ajaxSuccessHandler)
                        .failureHandler(ajaxFailureHandler)
                        .loginProcessingUrl("/authentication")
                        .passwordParameter("password")
                        .usernameParameter("username")
                    .and()
                    .logout()
                        .deleteCookies("JSESSIONID")
                        .invalidateHttpSession(true)
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/")
                    .and()
                    .csrf().disable()
                    .anonymous().disable()
                    .authorizeRequests()
                    .antMatchers("/authentication").permitAll()
                    .antMatchers("/oauth/token").permitAll()
                    .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
                    .antMatchers("/user/*").access("hasRole('ROLE_USER')");
        }
    }
    
  2. ==============================

    2.시작한 CORS 구성은 Spring Boot로 올바른 방법이 아닙니다. WebMvcConfigurer bean을 등록해야합니다. 여기를 참조하십시오.

    시작한 CORS 구성은 Spring Boot로 올바른 방법이 아닙니다. WebMvcConfigurer bean을 등록해야합니다. 여기를 참조하십시오.

    봄 부팅 CORS 설정 예 :

    @Configuration
    @Profile("dev")
    public class DevConfig {
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**").allowedOrigins("http://localhost:4200");
                }
            };
        }
    
    }
    

    이렇게하면 기본 (보안 시작 없음) 스프링 부트 응용 프로그램에 대한 CORS 구성이 제공됩니다. CORS 지원은 Spring Security와 독립적으로 존재한다는 점에 유의하십시오.

    Spring Security를 ​​소개하고 나면 보안 설정으로 CORS를 등록해야합니다. 스프링 시큐리티는 기존의 CORS 구성을 선택하기에 충분히 똑똑합니다.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors().and()              
             ....
    

    필자가 설명한 첫 번째 옵션은 실제로 Spring Security를 ​​기존 애플리케이션에 추가하는 관점에서입니다. Spring Security Docfiles에서 설명하는 방법에는 CorsConfigurationSource 빈을 추가하는 것이 포함된다.

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                // by default uses a Bean by the name of corsConfigurationSource
                .cors().and()
                ...
        }
    
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
            return source;
        }
    }
    
  3. ==============================

    3.저는 React 기반의 웹 클라이언트를 가지고 있고, 백엔드 REST API는 Spring Boot Ver 1.5.2를 실행하고 있습니다.

    저는 React 기반의 웹 클라이언트를 가지고 있고, 백엔드 REST API는 Spring Boot Ver 1.5.2를 실행하고 있습니다.

    localhost : 8080에서 실행중인 클라이언트의 모든 컨트롤러 경로 요청에서 CORS를 신속하게 활성화하려고했습니다. 내 보안 구성 내에서 FilterRegistrationBean 유형의 @Bean을 추가하고 쉽게 작동하도록했습니다.

    다음은 코드입니다.

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class AuthConfiguration extends WebSecurityConfigurerAdapter {
    
    ....
    ....
    
      @Bean
      public FilterRegistrationBean corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin(corsAllowedOrigin); // @Value: http://localhost:8080
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
      }
    
      @Override
      protected void configure(HttpSecurity httpSecurity) throws Exception {    
          httpSecurity
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // **permit OPTIONS call to all**
            ....
      }
    
    ....
    ....
    
    }
    

    여기에서 Spring Boot 문서를 참조 할 수 있습니다.

  4. ==============================

    4.인터셉터를 사용하여이 작업을 수행 할 수도 있습니다.

    인터셉터를 사용하여이 작업을 수행 할 수도 있습니다.

    예외를 사용하여 요청의 수명주기를 종료하는지 확인하십시오.

    @ResponseStatus (
        value = HttpStatus.NO_CONTENT
    )
    public class CorsException extends RuntimeException
    {
    }
    

    그런 다음 인터셉터에서 모든 OPTIONS 요청에 대한 헤더를 설정하고 예외를 throw합니다.

    public class CorsMiddleware extends HandlerInterceptorAdapter
    {
        @Override
        public boolean preHandle (
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler
        ) throws Exception
        {
            if (request.getMethod().equals("OPTIONS")) {
                response.addHeader("Access-Control-Allow-Origin", "*");
                response.addHeader("Access-Control-Allow-Credentials", "true");
                response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS, DELETE");
                response.addHeader("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,Authorization,If-Modified-Since,Cache-Control,Content-Type");
                response.addHeader("Access-Control-Max-Age", "3600");
                response.addHeader("charset", "utf-8");
                throw new CorsException();
            }
    
            return super.preHandle(request, response, handler);
        }
    }
    

    마지막으로 모든 경로에 인터셉터를 적용합니다.

    @Configuration
    public class MiddlewareConfig extends WebMvcConfigurerAdapter
    {
        @Override
        public void addInterceptors (InterceptorRegistry registry)
        {
            registry.addInterceptor(new CorsMiddleware())
                    .addPathPatterns("/**");
        }
    }
    
  5. ==============================

    5.빠른 지역 개발을 위해 필요한 경우이 주석을 컨트롤러에 추가하십시오. (필요에 따라 오프 코스 변경 출처)

    빠른 지역 개발을 위해 필요한 경우이 주석을 컨트롤러에 추가하십시오. (필요에 따라 오프 코스 변경 출처)

    @CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
    
  6. ==============================

    6.보안이 사용 가능하면 OPTIONS 요청은 기본적으로 차단됩니다.

    보안이 사용 가능하면 OPTIONS 요청은 기본적으로 차단됩니다.

    추가 빈을 추가하면 프리 플라이트 요청이 올바르게 처리됩니다.

       @Bean
       public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() {
          return configurer -> {
             List<RequestMatcher> matchers = new ArrayList<>();
             matchers.add(new AntPathRequestMatcher("/**", "OPTIONS"));
             configurer.requestMatchers(new OrRequestMatcher(matchers));
          };
       }
    

    응용 프로그램에 따라 잠재적 악용으로 열릴 수 있습니다.

    더 나은 솔루션을위한 열린 문제 : https://github.com/spring-projects/spring-security/issues/4448

  7. ==============================

    7.방금 비슷한 문제가 있었는데, http : // localhost : 3000에서 실행중인 React에서 프론트 엔드의 요청을 http : // localhost : 8080에서 실행중인 SpringBoot의 백엔드로 실행하려고했습니다. 나는 두 가지 오류가 있었다 :

    방금 비슷한 문제가 있었는데, http : // localhost : 3000에서 실행중인 React에서 프론트 엔드의 요청을 http : // localhost : 8080에서 실행중인 SpringBoot의 백엔드로 실행하려고했습니다. 나는 두 가지 오류가 있었다 :

    액세스 제어 허용 원점

    이것을 RestController에 추가하여 매우 쉽게 해결했습니다.

    @CrossOrigin(origins = ["http://localhost:3000"])
    

    이 문제를 해결 한 후에이 오류가 발생하기 시작했습니다. 응답의 'Access-Control-Allow-Credentials'헤더의 값은 ''이어야하며 'true'여야합니다.

    액세스 제어 허용 자격 증명

    이 방법은 두 가지 방법으로 해결할 수 있습니다.

    const response = fetch ( 'http : // localhost : 8080 / your / api', {신임장 : '동일 출처'})를 기다린다.

    희망이 도움이 =)

  8. from https://stackoverflow.com/questions/40286549/spring-boot-security-cors by cc-by-sa and MIT license