CSRF 토큰

CSRF 토큰

생성일
Oct 19, 2024 09:10 AM
최종 편집 일시
Last updated October 19, 2024
태그
CS

CSRF (Cross-Stie Request Forgery Token)?

CSRF 공격은 악의적인 웹사이트에서 피해자에게 특정 요청을 강제하여 다른 사이트에서 무단으로 수행되도록 하는 공격이다.
CSRF는 사용자가 이미 인증된 상태일 때 공격자가 사용자의 권한을 악용해 공격 대상 사이트에 임의의 요청을 보내는 방식으로 이루어진다.
이를 방지하기 위한 메커니즘 중 하나가 CSRF 토큰이다.

CSRF 공격의 예시

  1. 사용자가 은행 웹사이트에 로그인하여 세션이 유지된 상태이다.
  1. 악의적인 웹사이트(피싱 사이트)에 방문한 사용자가 어떤 버튼을 클릭하게 한다.
  1. 그 버튼은 은행 사이트로 특정 금액을 송금하라는 요청을 서버로 보낸다. (사용자는 이 요청이 갔다는 것을 인지하지 못한다.)
  1. 사용자의 세션이 은행 사이트에서 유지되고 있기 때문에 이 요청은 합법적인 것처럼 처리될 수 있다.
CSRF는 이런 식으로 사용자의 인증 정보를 악용으로 무단으로 서버에 요청을 보내는 공격이다.

CSRF 토큰의 역할

CSRF 토큰은 이런 공격을 방지하기 위해 사용된다.
서버는 사용자의 요청이 해당 서버에서만 발생한 정당한 요청인지 확인하기 위해, 요청에 토큰을 추가하고 이를 검증하는 방식으로 CSRF를 방지한다.

CSRF 토큰의 동작 방식

  1. 토큰 생성
    1. 사용자가 서버에 접근하거나 페이지를 요청하면, 서버는 고유한 CSRF 토큰을 생성하여 사용자에게 제공한다.
    2. 이 토큰은 서버 측 세션에 저장되고, HTML 폼에 hidden input 필드나 HTTP 헤더를 통해 사용자에게 전송된다.
  1. 토큰 전송
    1. 사용자가 폼을 제출하거나 서버로 요청을 보낼 때, 이 CSRF 토큰이 함께 전송된다.
  1. 토큰 검증
    1. 서버는 요청을 받으면, 요청에 포함된 CSRF 토큰이 서버에 저장된 토큰과 일치하는지 확인한다.
    2. 토큰이 일치하면 요청을 처리하고, 일치하지 않으면 CSRF 공격으로 간주하여 요청을 차단한다.

CSRF 토큰의 특징

  1. 고유성
    1. 각 사용자 세션마다 고유한 토큰을 부여하여 악의적인 사용자가 임의로 토큰을 예측할 수 없도록 한다.
  1. 짧은 유효 기간
    1. 토큰의 유효 기간을 짧게 설정하여 공격 가능성을 줄인다.
  1. 양방향 통신
    1. 클라이언트와 서버 간에 토큰이 전송되고 검증되는 과정에서 CSRF 공격을 방지한다.
 

CSRF 토큰의 구현

Spring Security에는 CSRF 보호 기능이 기본적으로 활성화되어 있다. CSRF 토큰은 자동으로 생성되고 폼 제출 시 함께 전송된다.
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf() .and() .authorizeRequests() .anyRequest().authenticated(); } }
프론트에서 요청을 할 때는 HTTP 헤더에 X-CSRF-TOKEN 키로 토큰값을 value로 넣어서 보내면 된다.

CSRF 토큰과 JWT 사용

JWT 기반 인증에서는 CSRF 토큰이 필요하지 않다고 생각하는 경우가 있다.
JWT가 클라이언트에 저장되어 있고, 서버가 상태를 저장하지 않기 때문이다.
그러나, JWT가 쿠키에 저장되는 경우에는 CSRF 공격에 취약할 수 있기 때문에 CSRF 토큰이 필요할 수 있다.
이 때는 JWT를 헤더에 저장하거나, 별도의 CSRF 토큰을 발급해 쿠키와 함께 사용한다.
 

쿠키로 JWT를 담았을 때 위험한 이유?

JWT를 저장하는 방법 중 하나는 쿠키에 저장하는 것이다.
쿠키는 클라이언트(브라우저)에 저장되며, 이후 해당 도메인에 요청이 발생할 때 자동으로 요청에 포함된다.
사용자가 어떤 웹사이트에 방문해 요청을 보내면, 브라우저는 해당 사이트에 관련된 모든 쿠키를 자동으로 포함한다.
이 때문에 피싱 사이트나 악의적인 스크립트를 통해 사용자가 해당 쿠키를 포함한 요청을 원하지 않는 사이트로 보내도록 유도할 수 있다.
브라우저가 자동으로 JWT가 포함된 쿠키를 해당 사이트로 보낼 것이고 서버는 요청이 정상이라고 생각하게 된다.
따라서 JWT를 로컬 스토리지나 세션 스토리지에 저장하고 요청 시 Authorization 헤더에 넣어서 보내는 방식으로 사용하면 CSRF 공격에 더 안전하다.
단순히 사용자를 속여서 요청을 보내는 것으로는 헤더에 JWT를 포함할 수 없기 때문에 무단으로 요청을 보내는 것이 어렵다.
따라서 JWT를 쿠키에 저장하는 경우, CSRF 공격을 방지하기 위한 조치로 CSRF 토큰을 함께 사용하는 방법을 선택할 수 있다.