programing

CSRF 보호가 Spring Security 6과 함께 작동하지 않음

elecom 2023. 7. 7. 18:34
반응형

CSRF 보호가 Spring Security 6과 함께 작동하지 않음

Spring Boot 3와 Spring Security 6으로 프로젝트를 업그레이드했는데 업그레이드 이후로 CSRF 보호가 더 이상 작동하지 않습니다.

다음 구성을 사용합니다.

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(authorize -> authorize
            .anyRequest().authenticated())
        .httpBasic(withDefaults())
        .sessionManagement(session -> session
            .sessionCreationPolicy(SessionCreationPolicy.ALWAYS))
        .csrf(csrf -> csrf
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
        .build();
}

@Bean
public UserDetailsService userDetailsService() {
     UserDetails user = User.builder().username("user").password("{noop}test").authorities("user").build();
     return new InMemoryUserDetailsManager(user);
}

웹 페이지에는 단추가 하나만 있습니다.

<button id="test">Test CSRF</button>

그리고 다음 자바스크립트 코드:

document.querySelector("#test").addEventListener('click', async function() {
  console.log('Clicked');
  // This code reads the cookie from the browser
  // Source: https://stackoverflow.com/a/25490531
  const csrfToken = document.cookie.match('(^|;)\\s*XSRF-TOKEN\\s*=\\s*([^;]+)')?.pop();
  const result = await fetch('./api/foo', {
    method: 'POST',
    headers: {
      'X-XSRF-Token': csrfToken
    }
  });
  console.log(result);
});

Spring Boot 2.7.x에서는 이 설정이 잘 작동하지만 프로젝트를 Spring Boot 3 및 Spring Security 6으로 업그레이드하면 다음 디버그 로그와 함께 403 오류가 발생합니다.

15:10:51.858 D         o.s.security.web.csrf.CsrfFilter: Invalid CSRF token found for http://localhost:8080/api/foo
15:10:51.859 D   o.s.s.w.access.AccessDeniedHandlerImpl: Responding with 403 status code

제 생각에는 이것이 #4001의 변경 사항과 관련이 있는 것 같습니다.하지만 코드를 무엇으로 변경해야 하는지, XOR를 해야 하는지 이해가 되지 않습니다.

CSRF 토큰의 신규 로딩 지연으로 인한 것인지 확인했지만, 버튼을 두 번 클릭해도(XSRF-TOKEN 쿠키가 설정되어 있는지 확인) 여전히 작동하지 않습니다.

최근 참조 설명서에 이 문제에 대한 솔루션을 보여주는 5.8(6.0 준비)로 마이그레이션하기 위한 섹션을 추가했습니다.

TL;DR 각도 사용 참조JS 또는 다른 Javascript 프레임워크입니다.

위의 가 "AngularJS("AngularJS")"를 입니다.XSRF-TOKEN쿠키를 직접 만듭니다.스프링 보안 6 이전에는 문제가 없었습니다.그러나 유감스럽게도 쿠키는 실제로 원시 토큰을 유지하는 데 사용되며 Spring Security 6에서는 기본적으로 원시 토큰이 허용되지 않습니다.이상적으로 프런트 엔드 프레임워크는 토큰을 얻기 위해 다른 소스를 사용할 수 있습니다. 예를 들어,X-XSRF-TOKEN응답 헤더입니다.

그러나 Spring Security 6을 사용하더라도 이러한 응답 헤더가 즉시 제공되지는 않습니다. 제안할 만한 가치가 있는 향상 기능이 될 수도 있습니다.자바스크립트 프레임워크는 기본적으로 사용할 수 없기 때문에 아직 그러한 향상을 제안하지 않았습니다.

지금은 위에 링크한 섹션에서 제안한 대로 원시 토큰을 허용하도록 Spring Security 6을 구성하여 문제를 해결해야 합니다.할 수 해서 제은원토시제수계사다용합니속있만지안을 합니다.XorCsrfTokenRequestAttributeHandler속성의 요속의해예버전된시성청)을 사용할 수 있도록 .request.getAttribute(CsrfToken.class.getName())또는request.getAttribute("_csrf")BREATH에 할 수 ), CSRF BREASH는 HTML입니다.

BREATION을 보다 철저하게 조사할 수 있는 신뢰할 수 있는 출처를 찾는 것이 좋습니다. 하지만 안타깝게도 저는 그러한 출처를 주장할 수 없습니다.

지역사회가 스프링시큐리티 6를 소비하기 시작하면 상황이 빠르게 바뀔 수 있기 때문에 현재로서는 스프링시큐리티 이슈를 주시할 것을 권합니다. 필터를 CSRF 관련 문제를 추적하는 가능한 방법으로 사용할 수 있습니다.

스프링 부츠를 사용한 각진 애플리케이션이 있습니다.Spring-boot 3(Spring Security 6)으로 마이그레이션하려고 했습니다.그리고 우리는 같은 문제에 직면했습니다.

우리는 이 질문의 답에서 나온 몇 가지 해결책을 포함하여 많은 방법을 시도했지만 실패했습니다.시간을 보낸 후에 우리는 봄 보안 문서에서 해결책을 찾았습니다.

우리가 해야 할 일은, 설정하는 것입니다.CsrfRequestAttributeNamenull구성에서.

requestHandler.setCsrfRequestAttributeName(null);

실제로 일어난 일:
CsrfToken은 Spring Security 버전 5의 각 요청에 기본적으로 로드됩니다.즉, 일반적인 설정에서는 모든 요청(필요하지 않은 요청도 포함)에 HttpSession을 읽어야 합니다.

Spring Security 6의 기본 동작은 CsrfToken 조회를 필요할 때까지 연기하는 것입니다.

우리의 애플리케이션은 항상 토큰이 필요합니다.따라서 5.8 기본값을 선택해야 합니다.

예제 코드는 다음과 같습니다(문서 참조).

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
    CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
    // set the name of the attribute the CsrfToken will be populated on
    requestHandler.setCsrfRequestAttributeName(null);
    http
        // ...
        .csrf((csrf) -> csrf
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .csrfTokenRequestHandler(requestHandler)
        );
    return http.build();
}

저는 현재 이 문제를 해결하기 위해 사용하지 않도록 설정했습니다.XorCsrfTokenRequestAttributeHandler다음과 같이:

.csrf(csrf -> csrf
    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
    // Added this:
    .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()))

그러나 이는 제가 BREATH 공격에 취약하다는 것을 의미합니다.

감사합니다!JHipster + Spring Boot 3 앱에서 비슷한 프로젝트를 해결하는 데 사용할 수 있었습니다.하지만 최근에 학급 이름이 바뀌었을 수도 있는 것 같습니다.다음은 제가 사용해야 했던 것입니다.

.csrf(csrf -> csrf
    .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
    .csrfTokenRequestHandler(new ServerCsrfTokenRequestAttributeHandler()))

Spring Security 6.0.1 및 Spring Boot 3.0.2에서 승인된 응답의 지침을 따르는 것은 첫 번째 요청에서 실패하지만 그 이후에는 성공합니다.첫 번째 요청에서 실패하는 이유는 보호된 메서드가 호출될 때까지 토큰의 쿠키가 생성되지 않기 때문입니다.그 이유는 방법이기 때문입니다.CookieCsrfTokenRepository.saveToken다음과 같은 경우에만 호출됩니다.CsrfFilter 출들deferredCsrfToken.get()POST, PUT, PATCH 및 DELETE 메호출됩니다만서서에드▁post다니▁put됩▁delete출호▁patch,.유감스럽게도 현재 구현에서는 클라이언트가 첫 번째 요청에 실패할 것으로 예상해야 합니다.이전 버전의 Spring Security에서는 토큰의 쿠키가 GET, HEAD 또는 OPTIONS 요청에 대한 응답에 포함될 것으로 기대했습니다.

@steve-reisenberg가 지적한 문서는 서블릿에 맞게 수정되었습니다.

웹 플럭스 앱에 대한 적응은 다음과 같습니다(예:spring-cloud-gateway):

http.csrf((csrf) -> csrf
        .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
        .csrfTokenRequestHandler(new XorServerCsrfTokenRequestAttributeHandler()::handle));

는 (서버)CsrfTokenRequestAttributeHandler를 참조하는 답변과 달리) CSRF와 BREATH 모두로부터 보호해야 합니다.

승인된 답변을 사용하면 Spring Security를 사용하여 CSRF를 요구하는 테스트가 중단됩니다.SecurityMockMvcRequestPostProcessors.crsf()사용할 수 있는 것은CsrfTokenRequestAttributeHandler또는XorCsrfTokenRequestAttributeHandlerSpring Boot의 CSRF 구성에서 둘 다 양성 테스트 결과를 제공합니다.

허용된 답변을 사용하면 Angular가 작동하지만 검정은 중단됩니다.

은 그서현유해결은책한을 사용하는 .CsrfTokenRequestAttributeHandlerSpring Security의 BREATH 보호 기능을 효과적으로 비활성화할 수 있습니다.

CSRF 토큰을 헤더와 함께 JavaScript를 통해 전송해야 하는 다른 시나리오에 대해 문서에 명확하지 않은 문제를 만들었습니다.HTML 내부에 React 구성 요소를 주로 탑재하는 것과 같은 다중 페이지 앱이 있다면 유용할 수 있습니다.

기본적으로 필요한 것은 기본 CSRF 구성을 사용하여 X-CSRF-TOKEN 헤더를 사용하는 것입니다.

https://github.com/spring-projects/spring-security/issues/13009

언급URL : https://stackoverflow.com/questions/74447118/csrf-protection-not-working-with-spring-security-6

반응형