Spring/Spring Security

[Spring Security] 5-1. 보안: CSRF

noahkim_ 2023. 10. 6. 20:28

1. CSRF 공격이란?

  • Cross-Site Request Forgery (사이트 간 요청 위조 공격)
  • 공격자가 사용자를 속여, 위조된 사이트에서 클릭을 통해 의도하지 않은 요청을 보내게 만드는 공격
  • ✅ 사용자가 로그인한 상태일 경우, 브라우저가 해당 사이트에 요청을 보낼 때 세션 쿠키를 자동으로 포함하는 점을 이용함

 

예시) 은행 위조 사이트

더보기
  • 사용자가 은행 웹사이트에서 계좌이체를 마친 뒤에도 로그인 세션이 유지되고 있다고 가정한다.
  • 이후 사용자는 이메일을 확인하던 중, 모르는 사람이 보낸 링크를 별다른 의심 없이 클릭한다.
    • 링크를 통해 이동한 웹페이지에는 “버튼을 누르면 상품을 받을 수 있다”는 문구가 표시되어 있었음
    • 사용자는 해당 버튼을 클릭한다.
  • 하지만 이 버튼은 실제로는 공격자가 미리 만들어둔 은행 송금 요청을 전송하도록 구성되어 있다.
  • 송금 요청은 인증된 사용자만 접근할 수 있는 보안 URL이지만, 사용자의 브라우저에는 은행 로그인 세션 쿠키가 아직 남아 있다.
    • ❗️ 브라우저는 은행 웹사이트로 요청을 보낼 때 해당 쿠키를 자동으로 함께 전송한다.
  • 사용자의 브라우저가 인증 쿠키를 자동으로 전송하는 특성을 이용해, 사용자가 의도하지 않은 송금 요청을 은행 서버에 전달한다.
    • ❗️ 공격자는 사용자의 쿠키 값을 직접 읽거나 탈취하지 않아도 된다.
  • 은행 서버에 별도의 CSRF 방어가 없다면, 서버는 이 요청을 정상적으로 로그인한 사용자가 보낸 요청으로 오인할 수 있다.
  • 그 결과 사용자는 자신도 모르게 공격자에게 금액을 송금하는 피해를 입게 된다.

 

2. CSRF 방어 방법

Safe HTTP Method 준수

  • CSRF 공격을 방지하기 위해 서버의 상태를 변경하지 않는 안전한 메서드를 사용해야 함
  • ✅ GET, HEAD, OPTIONS, TRACE

 

Synchronizer Token Pattern

  • 사용자가 상태 변경 요청을 보낼 때, 서버가 발급한 CSRF 토큰을 함께 제출하도록 하는 방식
  • 서버는 예측하기 어려운 CSRF 토큰을 생성하고, 사용자 세션에 보관함 (HttpSessionCsrfTokenRepository)
  • ✅ 브라우저는 '/csrf' 요청을 통해 CSRF 토큰을 전달받음
    • 클라이언트는 상태 변경 요청 전에 서버가 발급한 CSRF 토큰을 발급받아야 함
    • ❗️ Same-Origin Policy 때문에 공격자는 읽지 못함.
    • ➡️ CORS 정책을 함부로 풀지 않도록 설정해야 함
  •  CSRF Token은 브라우저에 쿠키 형태로 보관되지 않습니다
    • 브라우저 메모리 어딘가에 저장됨
    • 요청 시, 'X-CSRF-TOKEN'라는 HTTP 요청 헤더로 함께 전송함
  • ➡️ 요청으로 들어온 _csrf 값의 비교를 통해 유효성을 검증합니다.

 

동작 과정

더보기
  1. 서버가 사용자 세션과 연결된 CSRF 토큰을 생성한다.
  2. 정상 웹페이지에 CSRF 토큰을 포함해 클라이언트에 전달한다.
  3. 클라이언트는 상태 변경 요청에 CSRF 토큰을 함께 전송한다.
  4. 서버는 자신이 보관한 토큰과 요청으로 전달된 토큰을 비교한다.
  5. 토큰이 일치하면 요청을 허용하고, 없거나 일치하지 않으면 거부한다.

 

SameSite Attribute

  • 브라우저가 쿠키를 교차 사이트 요청에 포함할지 제한하는 쿠키 속성
  • ✅ Strict: 동일 사이트 요청에만 쿠키 전송
  •  Lax: 동일 사이트 요청에만 쿠키 전송 (단, 외부 링크의 최상위 GET 이동만 허용)
  • ➡️ 공격자 사이트에서 발생한 상태 변경 요청에 인증 쿠키가 자동으로 첨부되는 것을 제한하므로 CSRF 방어의 효과를 얻음.

 

Content-Type 검증

  • 서버가 상태 변경 요청에서 허용할 Content-Type를 제한해 CSRF 공격 경로를 줄이는 보조 방어 방식
  • ➡️ application/json 형태로 보내면 CORS Preflight 검증이 발생하므로 위조 사이트의 요청을 제한할 수 있음

 

3. CSRF 고려사항

Login

  • 공격자가 피해자의 브라우저를 이용해 공격자 자신의 계정으로 로그인 요청을 보내는 공격
  • 피해자는 자신이 정상적으로 로그인한 것으로 생각하고 민감정보 입력을 의심없이 입력할 수 있음
  • 그러나 실제로는 공격자 계정에 로그인된 상태이므로, 입력한 정보가 공격자 계정에 저장될 수 있음
  • ➡️ 로그인 요청에도 CSRF 토큰 검증 적용
  • ➡️ 로그인 성공 시 기존 세션 교체 (Session Fixation 방지)
  • ➡️ session timeout: 장시간 방치된 세션의 위험을 줄이기

 

Session Timeout

  • CSRF Token은 session에 포함됩니다.
  • ✅ 세션이 만료되면 인증 정보와 함께 기존 CSRF 토큰도 무효화됨
  • ➡️ session이 곧 만료되면 사용자에게 알리기 (재로그인 안내)
  • ➡️ CSRF Token을 쿠키에 저장하기
    • 공격자에 의해 접근이 가능하므로 여러 보안장치를 가져야 합니다
    • CORS, SameSite, Secure, 제한적 Path 및 Domain 등

 

Multipart

  • Multipart request로부터 CSRF 공격을 방어하는데 문제가 있습니다.
  • ⚠️ CSRF Token을 Body에 둘 경우, 확인을 위해 Body를 읽는 순간 Multipart 파일이 업로드됨 (자원 소비)
  • ⚠️ CSRF Token을 URL에 둘 경우, 토큰이 노출될 위험이 있음
  • ➡️ CSRF Token을 X-CSRF-TOKEN 요청 헤더에 두기

 

참고