CSRF 공격과 CSRF Token에 대하여
in Computer Science on Security
들어가기에 앞서
CSRF에 대해 알아보기에 앞서 JWT 토큰에 대한 이야기를 잠깐 하려고 한다.
왜 CSRF 관려 글에 JWT 토큰을 언급하는지는 추후에 설명하도록 하겠다.
JWT 토큰이란
JWT, JSON WEb Token의 약자로 토큰 기반 인증에 사용되는 토큰을 의미한다.
JWT 토큰은 문자열로 구성되어있기 때문에 HTTP의 헤더든, URL이든, Body든 어디에도 위치할 수 있다는 장점이 있다.
이러한 토큰 기반 인증 방식은 기존의 세션 방식의 인증에 비해 여러 장점을 갖고 있다.
기존 서버 - 클라이언트 구조에서는 세션을 서버가 저장하게 되고 이는 유저가 많아질 수록 서버에 메모리에 저장되는 정보가 많아지므로 과부하를 가져올 수 있다.
그리고 세션 정보를 클라이언트가 쿠키에 저장하게 되는데, 이 쿠키는 stateful하기 때문에 이 정보를 서버와 클라이언트가 모두 갖고 있어야한다는 단점이 있다.
그 외에도 확장성 문제(분산 시스템 설계의 어려움)나 CORS 문제도 여전히 존재한다.
이에 비해 토큰 기반 인증방식은 stateless한 성질을 갖고 있어 기존 세션 인증 방식에 비해 가볍고 유연한 장점을 갖고 있다.
토큰 기반 인증방식에서 서버는 토큰을 발행만 하고 저장은 클라이언트만 한다. (물론 이 방식이 앞으로의 문제점을 초래하게 된다.)
서버 - 클라이언트의 종속성에 비해 토큰 기반 인증은 분산 환경에서 더욱 유연하게 사용할 수 있기 때문에 최근 인증 방식으로 많이 사용하고 있는 기법이기도 하다.
JWT 토큰의 문제점
그럼 무조건 JWT 토큰이 좋은거 아니야? 라고 생각할 수 있지만 물론 JWT 토큰도 단점이 존재한다.
TOKEN 자체의 문자열 길이가 길기 때문에 payload 데이터가 커진다.
Session ID보다 Token의 문자열 길이가 더 길기 때문에 어쨌든 리퀘스트에 이러한 긴 토큰 정보가 포함되는 것 자체가 유쾌한 상황은 아니다.
JWT 토큰은 정보를 갖고 있다.
JWT 토큰은 토큰 내부에 사용자 정보를 저장하게 되는데 이 토큰이 탈취당하게 되면 이러한 사용자 정보도 고스란히 해커의 손에 넘어가게 된다.
때문에 중요한 정보는 토큰 내에 포함시키지 않는 것이 좋다.
한번 발급된 JWT 토큰은 계속해서 사용할 수 있다.
해커가 한번 토큰을 털어버리면 계속해서 사용할 수 있기 때문에 무자비하게 정보를 털어가는 것이 가능하다.
이를 해결하기 위해 Access Token의 유효 기간을 짧게 하고 Refresh Token을 발급해주면 비교적 피해를 줄일 수 있지만 이 역시도 완벽한 방법은 아니다.
토큰은 일반적으로 브라우저의 localStorage에 저장된다.
토큰을 localStorage에 저장한다는 말은 다시 말하면 XSS 공격에 취약해진다는 것을 의미한다.
localStorage는 스크립트를 사용해서 정보를 가져올 수 있다.
그러면 이 토큰을 쿠키에 저장하는 것은 어떨까?
쿠키는 기본적으로 httpOnly나 secure 속성과 같이 스크립트 실행을 막아줄 수 있는 기능이 존재한다.
그러나 쿠키에 저장한다고 하더라도 CSRF 공격에 여전히 취약하다.
자 서론이 길었는데 이 CSRF 공격이 오늘 소개할 내용이다.
CSRF ( Cross Site Request Forgery )
CSRF는 한 마디로 사용자의 의도와 관계 없이 행해지는 공격 기법을 의미한다.
여기서 말하는 공격의 예시는 다음과 같다.
사용자가 그저 버튼을 눌렀을 뿐인데 해커가 심어놓은 스크립트에 의해 내 계정의 인증과정을 거쳐서 나의 의도와 관계없이 내 블로그에 광고성 글이 올라간다는 것을 생각해보면 된다.
이러한 CSRF 공격은 여러 방어 방법이 있다. 대표적인 두 가지를 소개해보려고 한다.
Referer Check
백엔드에서 request의 referer를 확인하여 도메인이 일치하는지 검증하는 방법이다.
일반적으로는 Referer 체크 만으로도 대부분의 CSRF 공격을 막아낼 수 있다.
CSRF Token이란
CSRF Token은 임의의 난수를 생성하고 세션에 저장한다.
그리고 사용자의 매 요청마다 해당 난수 값을 포함시켜서 전송시킨다.
이후 백엔드에서는 요청을 받을 때 마다 세션에 저장된 토큰값과 요청 파라미터에 전달된 토큰 값이 같은지 검사한다.
스프링 시큐리티에서는 공식적으로 이 CSRF 공격에 대한 방어 기능을 시큐리티 모듈에서 제공해주고 있다.
Reference
https://stackoverflow.com/questions/34817617/should-jwt-be-stored-in-localstorage-or-cookie#:~:text=localStorage%20is%20subjected%20to%20XSS,then%20are%20subjected%20to%20CSRF
https://portswigger.net/web-security/csrf/tokens
https://itstory.tk/entry/CSRF-%EA%B3%B5%EA%B2%A9%EC%9D%B4%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-CSRF-%EB%B0%A9%EC%96%B4-%EB%B0%A9%EB%B2%95