[JWT] JWT 저장위치에 대한 고찰
Updated:
위 대화는 최근 같이 작업하는 클라이언트가 슬랙에 올린 질문과 그에대한 답변이었습니다.
현재로선 프론트에 대한 지식이 거의 없지만 local storage의 경우 javascript로 간단히 접근할 수 있기 때문에 과연 이 방법이 여러 공격으로 부터 안전할지에 대한 고민을 하게되었습니다.
JWT 발급 과정
보통의 jwt 발급과정은 다음과 같은 절차로 진행이 됩니다.
이와같이 발급받은 access token을 local storage에 저장한다는 것인데 이 외의 다른 저장방법에는 HTML5 web storage (Local, Session Storage)
, Cookies
가 있습니다.
- Local Storage
- Session Storage
- Cookies
이 세가지 방식 중에서 무엇을 선택해야 하는가에 대한 기준이 되는것은 결국 보안
입니다. 각각의 방식별로 취약한 부분이 존재하며 이를 어떻게 보완하느냐가 핵심이 될 것입니다. $($Session Storage의 경우 새로고침시에 데이터가 삭제된다는 점을 제외하면 local storage와 같기 때문에 묶어서 설명하겠습니다.)
HTML5 web storage
web storage는 브라우저에 데이터를 저장할 수 있는 방법입니다. HTML5에서 처음 등장하였으며 이전에는 쿠키를 통해 브라우저에 데이터를 저장하였습니다.
web storage를 사용하면 쿠키보다 더 많은 데이터를 저장할 수 있고 보안이 뛰어나다는 장점이 존재합니다.
크롬 개발자 도구를 통해 web storage에 값을 추가, 삭제, 수정이 가능하며 발급받은 jwt 토큰을 자바스크립트 localStorage 객체를 통해서 쉽게 저장할 수 있습니다.
// response.token 에 api 를 통해 받은 토큰 값이 정해져있다고 가정.
let token = response.token;
localStorage.setItem("token",token);
web storage에 저장된 토큰은 서버에 http 요청을 보낼때 같이 전달됩니다.
보통 HTTP를 통해 전달하면 Authrization 헤더에 Bearer 스키마로 함께 보내며 서버측에서는 이를 파싱하여 토큰을 확인하는 방식입니다.
Cookies
사용자 인증 과정을 마치고 나면 서버측에서는 HTTP Set-Cookie 헤더를 통해서 토큰을 보냅니다. 브라우저는 이를 통해 쿠키를 생성하고 쿠키에 토큰을 저장합니다.
이후에 API 요청을 하게되면 브라우저는 자동으로 이 쿠키를 실어서 보냅니다.
이러한 특징 덕분에 구현하는 입장에서도 편리하다는 장점이 있으며 HTTP-Only
옵션, Secure
옵션을 통해 보안성을 높일수 있습니다. $
($해당 옵션에 대해서는 뒤에서 설명하겠습니다.)
XSS $($Cross Site Scripting)
XSS 공격
은 해커가 악의적으로 웹페이지에 자바스크립트 코드를 심어 사용자의 정보를 탈취해 가는 공격을 말합니다.
일반적인 웹 어플리케이션의 경우 사용자로 부터 데이터를 입력받게 되는데 이 데이터에 해커가 스크립트를 심은 후 사용자가 게시글을 클릭하도록 유도합니다.
이렇게 되면 사용자의 쿠키 또는 local storage 값을 해커의 서버로 전송할 수 있는데, 이러한 방식을 통해 jwt값 또한 탈취될 위험이 존재합니다.
CSRF $($Cross-site request forgrey)
XSS가 사용자를 대상으로 한 공격이었다면 CSRF는 사용자의 의지와는 상관없이 해커가 사용자 권한을 탈취하여 생성, 수정, 삭제등의 요청을 수행하는 공격을 의미합니다. 예를 들어 설명해 보겠습니다.
해커는 fishinguser.hack 이라는 사이트를 제작하고 google.com을 사용하는 유저에게 그럴듯한 이메일을 보내서 열어보게 만들면 fishinguser.hack 해당 사이트에 접속하자마자 아래와 같이 googel.com에 http 요청을 보내게 하는 코드를 HTML에 삽입해 놓은 것 입니다.
<img src="http://google.com/api/changeUserName/idiot"
해커의 의도에 넘어간 사용자는 이 사이트에 접속하자 마자 자신도 모르는 사이에 google.com의 유저 이름을 변경하는 API를 호출하게 되는 것 입니다.
이때 이미 google.com에 접속해서 얻은 쿠키가 유요한 상태이기 때문에 이 요청에는 쿠키가 담아서 보내지게 되고 API는 쿠키의 토큰을 통해 인증여부를 확인하고 요청을 수행하게 되기 때문에 문제가 발생하게 되는 것 입니다.
JWT 저장소로 적합한 위치는?
Local storage의 경우 XSS 공격에, 쿠키의 경우 CSRF 공격에 취약하다는 것을 알 수 있었습니다. $($그렇다고 local storage가 CSRF에, 쿠키가 XSS에 안전한 것은 아닙니다.)
여러 자료를 찾아본 결과 개인적으로 쿠키에 jwt를 저장하는 방법이 안전하다고 생각합니다.
XSS의 경우 다방면에서 스크립트를 차단해야 하기 때문에 공격의 범위가 너무 넓습니다. 반면 CSRF의 경우 보다 쉽게 공격을 대처할 수 있는 방법들이 존재합니다.
1. 특정 함수를 통해서만 API에 대한 http 요청을 보낼수 있게 하는 방법
만약 특정 함수 $($토큰에 특정 해쉬값을 추가하여 전송) 를 통한 요청이 아닌 경우에는 인증을 거부합니다.
2. HTTP 헤더 분석
HTTP 헤더에 존재하는 origin값과 refer값을 확인하여 요청이 이상한 곳에서 들어온 것이 아닌지 확인합니다.
뿐만아니라 쿠키또한 자바스크립트로 조작이 가능하기 때문에 XSS에 취약하지만 local storage와 달리 옵션 설정을 통해 이를 막을 수 있습니다.
예를들어 쿠키생성시에 HTTPOnly
옵션을 주게되면 쿠키는 오직 HTTP로만 접근이 가능하며 자바스크립트로는 조작이 불가능 하게 됩니다.
여기서 Secure
옵션까지 포함해 준다면 http가 아닌 https로만 쿠키가 전송되게 설정하기 때문에 보안을 한층 높일수 있습니다.
Reference
http://lazyhoneyant.blogspot.com/2016/08/jwt.html
Leave a comment