CSRF

1. CSRF란?

CSRF는 웹사이트의 취약점을 이용하여 사용자가 의도하지 않는 행동을 유도하는 공격

 

Spring Security는 기본적으로 CSRF 보호를 제공하는데, 이는 Ajax 요청에도 적용됨. 따라서, 각 Ajax 요청에 CSRF 토큰을 포함해야 하며, 이를 누락하면 Spring Security는 해당 요청을 거부할 수 있음

 

Ajax : Asynchronous JavaScript and XML의 약자로, 웹 개발 기술의 하나입니다. Ajax를 사용하면 웹 페이지를 다시 로드하지 않고도 서버와 비동기적으로 데이터를 주고받을 수 있습니다. 이 기술을 통해 웹 애플리케이션은 사용자 경험을 더 동적이고 반응성이 뛰어나게 만들 수 있습니다.

 

CSRF에 대한 사용 방식

 

사용자가 뱅킹 웹 사이트에 로그인하여 세션을 시작합니다. 이 웹 사이트는 이 사용자를 쿠키를 통해 식별합니다.

 

사용자가 이 뱅킹 웹 사이트를 닫지 않고, 새 탭에서 공격자가 만든 웹 사이트에 접속합니다.

 

이 웹사이트에는 다음과 같은 코드가 있습니다. 이 코드는 뱅킹 웹 사이트에 대한 요청을 발생시킵니다.

<img src="http://bank.com/transfer?to=attacker&amount=1000">

 

브라우저는 이 요청을 보내고, 이때 뱅킹 웹 사이트에 대한 사용자의 쿠키도 함께 보냅니다. 즉, 이 요청은 사용자가 직접 보낸 것처럼 보입니다.

 

뱅킹 웹 사이트는 요청을 받아 사용자의 쿠키를 확인하고, 요청에 따라 1000달러를 공격자의 계좌로 이체합니다.

 

<img> 태그의 경우 ‘SOP 정책’에 영향을 받지 않고 요청을 보낼 수 있는 특성을 가지고 있고, 해당 코드를 실행하는 희생자의 브라우저는 저장된 쿠키를 자동적으로 담아서 보내게 됩니다.

 

SOP(동일 출처 정책, Same-Origin Policy) : 웹 보안의 중요한 개념으로, 웹 브라우저에서 실행되는 스크립트나 코드가 서로 다른 출처(origin) 간에 데이터를 주고받는 것을 제한하는 정책입니다. 이 정책은 악의적인 스크립트가 다른 도메인에서 정보를 훔치거나 변조하는 것을 방지하기 위해 설계되었습니다.

 

💡 서비스 서버에서는 해당 요청을 받아서 희생자가 원하지 않은 동작을 수행하게 될 것

 

2. CSRF 토큰

 

CSRF 공격이 가능하기 때문에, JWT 만을 이용해서 사용자를 인증한다고 했을 경우에 위험할 수 있음.

 

CSRF Token은 CSRF 공격을 방지하기 위해 사용되는 방법 중 하나. 이 토큰은 서버에 의해 임의로 생성되며, 클라이언트 측에 저장됨

  • 여기서 중요한 점은, CSRF Token은 이전 토큰들과 다르게 단순 난수 문자열 형식. 케이스에 따라 암호화(예: HMAC)를 수행할 수 있지만 일반적으로는 그대로 사용

 

2가지 방식이 존재

  1. HTML 폼에 담아서 보내는 방식
  2. 비멱등 요청이 일어날 때마다 CSRF Token 사용과 발급을 해주는 방식

 

2.1 HTML 폼에 담아서 보내는 방식

 

JWT는 HTTP Only Cookie에 담는 것을 가정

 

기본 동작 방식

  1. 클라이언트는 GET 메서드를 사용하여 애플리케이션 서버에 접근
  2. 서버는 CSRF 토큰을 생성하고 HTTP 세션에 저장. 생성된 CSRF 토큰은 HTML 형식의 숨겨진 태그를 사용하여 클라이언트와 연결됨
    • 숨겨진 태그를 사용하기 때문에 UI에서는 보이지 않고, 관리자 도구에서 소스 코드를 통해 확인할 수 있음
  3. 클라이언트는 HTML 양식의 버튼을 클릭하여 애플리케이션 서버에 요청을 보냄. CSRF 토큰은 HTML 형식의 숨겨진 필드에 포함되어 있으므로 CSRF 토큰 값이 요청 매개 변수로 전송됨
  4. 서버는 요청 파라미터에 지정된 CSRF 토큰 값과 HTTP POST 메서드를 사용하여 액세스 할 때 HTTP 세션에 유지된 CSRF 토큰 값이 동일한지 확인. 토큰 값이 일치하지 않으면 잘못된 요청으로 오류가 발생

 

위의 로직이 성립하려면 SPA이 아닌 애플리케이션에서 동작을 해야 함

 

SPA : 웹 애플리케이션이나 웹사이트의 한 유형으로, 사용자가 처음 페이지를 로드한 후 추가적인 페이지 로딩 없이도 동적으로 콘텐츠를 업데이트하는 방식으로 동작합니다. 전통적인 다중 페이지 애플리케이션(MPA)과는 달리, SPA에서는 새 페이지를 불러오기 위해 전체 페이지를 다시 로드하지 않고, 자바스크립트를 사용해 필요한 콘텐츠만 갱신합니다.

 

장점: CSRF 토큰을 리소스에 담아서 보냄으로써 토큰을 탈취하기가 힘듦

 

단점: 네트워크에 부담이 생김

 

2.2 비멱등 요청이 일어날 때마다 CSRF Token을 발급하는 방식

 

비멱등 요청(idempotent request)이란, 같은 요청을 여러 번 반복해서 보내더라도 결과가 동일하게 유지되는 요청을 의미합니다. 즉, 동일한 요청을 한 번 보내든, 여러 번 보내든 서버의 상태나 결과에는 변화가 없습니다.

HTTP에서 비멱등 요청의 예로는 GET, PUT, DELETE 요청이 있습니다. 각 요청의 비멱등성은 다음과 같이 설명할 수 있습니다:

  1. GET 요청: 특정 리소스를 가져오는 요청입니다. 여러 번 같은 GET 요청을 보내도 서버의 상태는 바뀌지 않으므로 비멱등성 요청입니다.
  2. PUT 요청: 특정 리소스를 생성하거나 업데이트하는 요청입니다. 예를 들어, 동일한 데이터를 여러 번 PUT 요청으로 보내더라도 서버에는 동일한 리소스가 존재하게 되며, 결과가 변하지 않으므로 비멱등성 요청입니다.
  3. DELETE 요청: 특정 리소스를 삭제하는 요청입니다. 동일한 DELETE 요청을 여러 번 보내도, 이미 삭제된 리소스는 더 이상 존재하지 않기 때문에 결과적으로 서버의 상태가 변화하지 않습니다. 따라서 DELETE도 비멱등성 요청으로 간주됩니다.

반면에 POST 요청은 비멱등성이 아닙니다. 동일한 POST 요청을 여러 번 보내면 서버의 상태가 요청 횟수에 따라 달라질 수 있습니다. 예를 들어, 같은 데이터로 여러 번 POST 요청을 보내면 새로운 리소스가 각각 생성될 수 있습니다. -chatGPT-

 

사용자가 로그인을 하고나서 JWT를 발급받을 때 CSRF Token을 쿠키에 저장해 두고, 사용자가 비멱등 요청을 보낼 때 JWT와 CSRF Token을 같이 보내서 두 토큰의 검증이 처리되면 요청을 처리하는 방식

 

기본 동작 방식

  1. 로그인을 할 때 JWT 와 CSRF Token을 같이 발급해 줍니다.
  2. JWT를 보유하고 있는 클라이언트가 비멱등 요청을 웹 서버로 보냄
  3. 비멱등 요청의 Request Header의 “X-CSRF-Token” 필드에 CSRF 토큰을 담고, JWT 토큰도 다른 헤더 필드에 담아서 인증 서버로 보냄
  4. 인증 서버에서는 JWT Filter → CSRF Filter 순으로 확인해 가면서 사용자를 검증
  5. 검증이 완료된 유저에 한해서 비멱등 요청을 처리

 

JWT Token을 먼저 검증하는 이유는 CSRF Token을 검증하기 위해서 유저의 고유한 정보(PK)가 필요한데 이것을 JWT로부터 받으려고 하는 것입니다. 또한, 로직 구성 자체만 봤을 때도 JWT는 사용자를 검증하는 것이고 CSRF Token은 사용자의 요청을 한번 더 검증해 주는 목적으로 사용하기 때문에 JWT 검증 후 CSRF Token을 검증하는 것이 맞다고 판단

 

참고

 

[Security] CSRF

여기서는 CSRF 공격이 무엇인지 알아보고, 이것을 예방하기 위해서 사용되는 CSRF Token에 대해서 정리를 할 것입니다.

velog.io

 

'Dev > Spring Security' 카테고리의 다른 글

JWT와 AccessToken, RefreshToken  (0) 2025.02.27
CORS  (0) 2025.02.11