Spring-Security

CSRF (Cross-Site Request Forgery): 개념, 방어 메커니즘, Spring Security에서의 처리

neal89 2025. 5. 29. 13:28

1. CSRF (Cross-Site Request Forgery)란?

CSRF는 사이트 간 요청 위조라는 의미로, 사용자가 로그인된 상태를 악용하여 사용자의 의지와 무관하게 공격자가 의도한 행위를 웹사이트에 요청하게 만드는 공격 기법입니다.

공격 원리 (이미지 자료 기반 설명):

이미지에서 설명된 CSRF 공격 흐름은 다음과 같습니다.

  1. 공격자: 악성 웹사이트를 만들고, 사용자에게 전달할 악성 링크를 생성합니다.
  2. 사용자: 공격자가 보낸 링크를 클릭하거나, 악성 웹사이트를 방문합니다.
  3. 공격용 웹사이트: 사용자의 브라우저를 통해 공격 대상이 되는 웹사이트에 요청을 보냅니다. 이때, 사용자가 이미 공격 대상 웹사이트에 로그인되어 있다면, 브라우저는 해당 웹사이트의 세션 쿠키를 자동으로 요청에 포함시켜 보냅니다.
  4. 공격 대상 서버: 브라우저가 보낸 요청에 사용자의 유효한 세션 쿠키가 포함되어 있으므로, 서버는 이 요청이 사용자의 정당한 요청이라고 오인하고 그대로 처리하게 됩니다. (예: 비밀번호 변경, 계좌 이체, 게시글 삭제 등)

이러한 공격은 사용자가 로그인된 상태에서 이루어지기 때문에 서버 입장에서는 정상적인 사용자의 요청으로 인식될 수 있습니다.

2. CSRF 방어: CSRF 토큰

CSRF 공격을 방어하는 가장 일반적이고 효과적인 방법은 **CSRF 토큰(Synchronizer Token)**을 사용하는 것입니다.

작동 원리:

  1. 서버는 사용자의 세션마다 고유한 CSRF 토큰을 발급하여 웹 페이지(주로 폼)에 숨겨진 필드(hidden field)나 HTTP 헤더에 포함시켜 클라이언트에게 전달합니다.
  2. 클라이언트(브라우저)가 데이터를 변경하는 요청(POST, PUT, DELETE 등)을 보낼 때, 이 토큰을 요청과 함께 서버로 다시 전송합니다.
  3. 서버는 수신된 요청의 토큰과 서버에 저장된(세션 등) 토큰을 비교하여 일치하는 경우에만 요청을 처리합니다. 만약 토큰이 일치하지 않거나 누락되었다면, 비정상적인 요청으로 간주하고 거부합니다.

어떤 이름으로 CSRF 토큰이 발행되는가?

Spring Security의 기본 CSRF 토큰 이름은 다음과 같습니다.

  • HTML 폼 필드 이름: _csrf
  • HTTP 헤더 이름: X-CSRF-TOKEN (Spring Security의 CsrfFilter가 이 헤더를 확인합니다.)

개발자는 필요에 따라 이러한 기본 이름을 변경할 수 있습니다.

3. 변경 요청 메서드에 대한 CSRF 토큰 검사

변경 요청 메서드에 대해서만 CSRF 토큰이 요청에 들어가는가?

네, 일반적으로 CSRF 토큰 검사는 서버의 상태를 변경하는 HTTP 메서드(State-Changing Methods)에 대해서만 적용됩니다. 이는 주로 다음과 같은 메서드를 포함합니다.

  • POST
  • PUT
  • PATCH
  • DELETE

GET 같은 안전한 메서드에는 토큰이 들어가는가, 아니면 검사를 안 하는가?

이미지 자료에서도 언급되었듯이, GET, HEAD, TRACE, OPTIONS와 같이 안전한(Safe) 메서드는 리소스의 상태를 변경하지 않는 비멱등(Idempotent)한 작업에 사용됩니다.

  • GET 요청에 CSRF 토큰이 포함되는가?
    • 일반적인 웹 페이지의 경우, GET 요청에는 CSRF 토큰이 포함되지 않는 것이 일반적입니다. CSRF 토큰은 주로 폼 제출 시 숨겨진 필드나 AJAX 요청 시 HTTP 헤더에 포함됩니다.
    • GET 요청은 브라우저의 주소창에 URL을 직접 입력하거나 링크를 클릭하는 것만으로도 발생할 수 있기 때문에, GET 요청에 CSRF 토큰을 요구하고 검증하는 것은 사용자 경험을 해치고 구현 복잡성을 증가시킬 수 있습니다.
  • GET 요청에 대해 토큰 검사를 안 하는가?
    • 네, Spring Security를 포함한 대부분의 CSRF 방어 메커니즘은 GET 요청에 대해서는 CSRF 토큰을 검사하지 않습니다. GET 요청은 서버의 상태를 변경할 목적으로 사용되지 않아야 한다는 HTTP 표준에 기반하기 때문입니다.
    • 만약 개발자가 실수로 GET 요청을 사용하여 서버의 상태를 변경하는 로직을 구현했다면, 이는 CSRF 공격에 취약해질 수 있습니다. 이러한 경우, GET 대신 POST 등의 메서드를 사용하도록 변경해야 합니다.

4. Spring Security에서 CSRF 처리 방법

Spring Security는 기본적으로 CSRF 방어 기능을 활성화하고 강력하게 지원합니다.

  • 기본 활성화: Spring Security 5.x 버전부터는 별도의 설정 없이 CSRF 보호가 기본적으로 활성화되어 있습니다. 모든 POST, PUT, PATCH, DELETE 요청에 대해 CSRF 토큰 검사를 수행합니다.
  • CsrfFilter: CSRF 보호는 CsrfFilter를 통해 구현됩니다. 이 필터는 요청이 들어올 때 CSRF 토큰의 유효성을 검사하고, 유효하지 않거나 누락된 토큰에 대해 AccessDeniedException을 발생시킵니다.
  • HTML 폼 통합: Spring Security는 Thymeleaf, JSP 등 템플릿 엔진을 사용할 때 자동으로 CSRF 토큰을 폼에 삽입할 수 있도록 지원합니다 (<input type="hidden" name="_csrf" value="..."/>).
  • AJAX 요청 처리: AJAX 요청의 경우, JavaScript를 사용하여 메타 태그 (<meta name="_csrf" content="..."/>, <meta name="_csrf_header" content="X-CSRF-TOKEN"/>) 등에서 토큰 값을 읽어 HTTP 요청 헤더(X-CSRF-TOKEN)에 포함시켜 전송해야 합니다.

CSRF 기능 활성화/비활성화 (이미지 자료 기반 예시):

  • CSRF 기능 활성화 (기본값):
    http.csrf(withDefaults()); // Spring Security 6.x+ 권장 방식
    // 또는 이전 방식: http.csrf().and()
    
    이것은 서버에 의해 생성된 모든 변경 요청이 토큰을 통해 전송되어야 하며, 서버는 이 토큰을 검증하여 요청의 유효성을 확인할 것임을 의미합니다.
  •  
  • CSRF 기능 비활성화:
    http.csrf(csrf -> csrf.disable()); // Spring Security 6.x+ 권장 방식
    // 또는 이전 방식: http.csrf().disable();
    
    CSRF 보호를 완전히 비활성화할 때 사용됩니다. API 서버처럼 세션을 사용하지 않거나, 자체적인 다른 보안 메커니즘이 있는 경우에 고려될 수 있지만, 일반적으로 권장되지 않습니다
  •  
  • 특정 엔드포인트 비활성화:
    http.csrf(csrf -> csrf.ignoringRequestMatchers("/api/**")); // Spring Security 6.x+ 권장 방식
    // 또는 이전 방식: http.csrf().ignoringAntMatchers("/api/**");
    
    특정 경로(예: /api/**와 같은 REST API 엔드포인트)에 대해서만 CSRF 보호를 비활성화할 때 사용됩니다. 이는 주로 세션 기반이 아닌 토큰 기반(JWT 등) 인증을 사용하는 REST API에서 유용합니다. 이미지 자료에서는 "CSRF 보호가 필요하지 않은 특정 엔드포인트를 비활성화"한다고 설명합니다

브라우저에서의 쿠키 처리와 CSRF:

이미지 자료에서 "반면에 쿠키에 토큰을 요구하는 것은 브라우저가 쿠키를 자동으로 요청에 포함시키기 때문에 효과적이지 않다고 볼 수 있다"고 언급된 부분은 중요한 오해의 소지를 해결합니다. CSRF 토큰은 쿠키에 저장되지 않고, 주로 서버 세션에 저장되거나 폼 필드/HTTP 헤더를 통해 전달됩니다. 공격자가 쿠키를 위조하여 요청에 포함시키는 것은 가능하지만, CSRF 토큰은 공격자가 예측하거나 조작할 수 없도록 설계되므로, 쿠키와 함께 전송되어도 서버에서 유효성을 검증함으로써 공격을 방어할 수 있습니다. 즉, 브라우저가 쿠키를 자동으로 보내는 특성 때문에 CSRF 공격이 가능한 것이고, 이를 막기 위해 Anti-CSRF Token이 필요한 것입니다.

요약하자면, CSRF는 로그인된 사용자의 세션을 악용하는 공격이며, Spring Security는 고유한 CSRF 토큰을 발행하고 검증하는 방식으로 이 공격을 효과적으로 방어합니다. 이 토큰은 주로 POST, PUT, PATCH, DELETE와 같은 상태 변경 메서드에 대해서만 검사가 이루어집니다.