TIL

24.09.06 TIL - CSRF

개발공명 2024. 9. 8. 13:48

오늘 배운 것

  • CSRF란?
  • CSRF 상황
  • CSRF 공격 예시
  • CSRF 공격 방지 방법

 

CSRF란?

CSRF는 Cross-site request forgery의 약자로 사이트 간 요청 위조라는 의미이다. 

 

웹 애플리케이션의 취약점을 이용해 사용자가 의도하지 않은 요청 보내도록 하는 공격 기법이다. 

 

공격자는 사용자가 인증된 상태를 악용해 사용자가 원하지 않는 행동 수행하게 만든다. 

 

공격자가 인증된 브라우저에 저장된 쿠키의 세션 정보를 활용해 웹 서버에 사용자가 의도하지 않은 요청 전달하는 것이다.

 

CSRF 공격은 생성된 요청이 사용자의 동의를 받았는지 확인할 수 없는 웹 애플리케이션의 CSRF 취약점을 이용한다.

 

공격자의 요청이 사용자의 요청인 것처럼 속이는 공격 방식이다.  

 

CSRF는 사용자가 인증한 세션에서 웹 애플리케이션이 정상적인 요청과 비정상적인 요청을 구분하지 못하는 점을 악용하는 공격 방식이다.

 

따라서 웹 애플리케이션이 사용자의 요청이 실제 사용자가 전송한 것인지 확인하지 않는 경우에 자주 발생한다.

 

CSRF 상황

  1. 사용자가 로그인
    1. 사용자가 A 웹 사이트에 로그인한다. 
  2. 세션 유지
    1. 로그인 후 세션 쿠키가 브라우저에 저장된다.
  3. 악성 B 웹 사이트 방문
    1. 사용자가 다른 B 웹 사이트에 방문한다. 
    2. B 웹 사이트는 CSFR 공격 코드를 포함하고 있다.
  4. 악의적인 요청 전송
    1. 악성 B 웹 사이트는 사용자의 세션 쿠키를 이용해 A 웹 사이트로 요청 보낸다. 
  5. A 웹 사이트 서버 처리
    1. A 웹 사이트의 서버는 요청을 정상적인 사용자의 요청으로 인식하고 처리된다. 

 

예를 들어 사용자가 로그인 된 상태에서 악의적인 웹 사이트를 방문한다. 

 

그러면 그 웹사이트가 사용자의 쿠키의 세션 정보를 이용해 은행 계좌에서 돈을 송금하게 하는 것이다. 

 

 

CSRF 공격 예시

공격자가 만든 악성 B 웹 사이트에 아래와 같은 코드가 작성되어 있는 것이다. 

 

악성 B 웹 사이트는 bank.com 사이트가 아니다. 

<!DOCTYPE html>
<html>
<body>
  <h1>Free Gift</h1>
  <img src="http://bank.com/transfer?amount=1000&to=attacker" style="display:none;" />
</body>
</html>

 

코드를 보면 img 태그에 display:none으로 되어 있다. 

 

사용자가 이 악성 B 웹 사이트에 방문하면 img 태그를 통해 src에 있는 요청이 자동으로 실행이 된다. 

 

src에 url을 보면 bank.com 으로 요청이 가는 것이다. 

 

사용자가 이미 bank.com에 로그인이 되어 있다면 이 요청은 인증된 상태로 처리된다. 

 

 

CSRF 공격 방지 방법

Referer 헤더 검증

  • 서버는 요청의 Referer 헤더를 확인하여 요청이 신뢰할 수 있는 출처에서 온 것인지 확인할 수 있다.
  • 그러나, Referer 헤더는 사용자가 조작할 수 있고, 일부 브라우저에서는 이 헤더를 포함하지 않을 수 있다.
  • 그래서 아래 방법이 나오게 되었다.

CSRF 토큰 사용

  • 가장 일반적인 방지 방법은 CSRF 토큰을 사용하는 것이다.
  • 서버는 각 요청에 대해 고유한 토큰을 생성하고, 이를 폼에 포함시킨다.
  • 서버는 요청이 들어올 때 이 토큰을 검증한다.

form 대신 API사용

  • API를 통해 JSON 데이터로 통신한다면 해당 이슈를 피할 수 있다.

 

정리

Spring Security에서 JWT를 사용할 때 CSRF를 disable 했었다.

 

왜 CSRF를 disable 해도 되는지 알아봤다. 

  • CSRF는 쿠키 기반 인증에서 주로 발생하는 공격이다. 
  • JWT 기반 인증에서는 서버가 사용자에게 토큰을 발급한다 .
  • 그리고 사용자는 그 토큰을 HTTP 요청의 Authorization 헤더에 포함시켜 서버로 보낸다. 
  • 이 방식은 쿠키와 달리 토큰을 클라이언트가 명시적으로 요청에 포함시켜야 한다. 
  • 그러므로 브라우저가 자동으로 토큰을 전송하는 방식이 아니다
  • 이로 인해 CSRF 공격에서 발생하는 자동 쿠키 전송 문제가 JWT에서는 발생하지 않는다고 한다. 
  • JWT를 쿠키에 넣어서 보내는 경우도 있는데 이 경우는 CSRF 공격에 취약할 수 있다고 한다. 
  • 그래서 JWT를 Response Header에 넣는 것이 좋을 것 같다. 
  • Response Header에 JWT를 넣으면 XSS 공격에 취약할 수 있어서 클라이언트는 XSS 방어 강화해야 한다고 한다. 

 

그리고 다른 도메인으로 쿠키를 보낼 때 SameSite를 none으로 설정하면 CSRF 공격에 취약하다고 했다. 

 

왜 CSRF 공격에 취약한지 알아봤다. 

  • 쿠키의 SameSite 속성은 웹 브라우저가 쿠키를 특정 요청에 포함시킬지 여부를 결정하는 중요한 보안 설정이다. 
  • SameSite 속성으로 none으로 설정하면 외부 사이트에서도 쿠키 전송 가능해진다. 
  • SameSite=None은 외부 도메인에서 이루어지는 요청에도 쿠키를 포함시킬 수 있음을 의미한다. 
  • 즉, 다른 도메인에서 사용자가 요청을 보낼 때도 해당 쿠키가 전송된다. 
  • SameSite=None을 설정하면, 사용자가 악성 사이트에 접속할 때 그 사이트가 사용자가 이미 로그인한 상태의 세션을 악용해 요청을 보낼 수 있다
  • 이때 쿠키는 자동으로 전송되므로 공격자는 해당 쿠키를 악의적인 요청과 함께 보낼 수 있어 CSRF 공격이 성공할 가능성이 커진다. 

 

쿠키를 사용할 때 이런 문제들이 있는 것 같다. 

 

따라서 세션 방식 보다는 JWT 방식을 사용하는 경우가 많은 것 같다. 

 

JWT를 쿠키에 넣어서 보내는 것보다 Response Header에 넣어서 보내는 것이 더 좋은 것 같다

 

CSRF 문제를 피할 수도 있고 다른 도메인에 쿠키를 보내기 위해 또 CSRF 공격 가능성을 높이지 않아도 되기 때문이다.