ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JWT와 세션
    분석과탐구 2023. 7. 22. 09:55

    Why avoiding LocalStorage for tokens is the wrong solutionJWT

    JWT는 토큰이다. 토큰은 일련의 문자열을 의미한다. JWT는 일련의 문자열을 서버와 클라이언트가 주고받아 서로 통신하기 위한 도구이다.

     

    JWT는 '헤더.페이로드.사인'으로 이루어진 문자열이다. 헤더, 페이로드는 json으로 이루어져 있고, 사인은 헤더와 페이로드를 시크릿키로 암호화한 값이다. 클라이언트와 서버가 주고받을 때 base64로 인코딩 되어 전송한다. 누군가 JWT를 얻었다면, base64 디코딩을 통하여 간단히 내용을 확인할 수 있다. 그래서 JWT 안에 중요한 데이터를 보관하는 것은 좋은 방향이 아니다.

     

    JWT는 위조방지 기능이 있는 토큰이다. 서버가 가진 시크릿키를 이용하여 헤더와 페이로드를 암호화한 결과를 사인에 저장하기 때문이다. 사인의 존재로 인해서 위조가 어려운 것이다. 누군가 JWT를 헤더나 페이로드를 바꾸더라도 사인과 어긋나므로 위조 방지 효과가 있다.

     

    그러므로, JWT의 쓰임새는 위조방지 기능이 있는 토큰으로써 현실의 지폐처럼, 놀이동산의 입장권처럼, 영화관의 표처럼 사용되는 것이 바람직하다. 위조방지만 확인하고 그 내용을 그대로 믿고 사용하는 것을 의미한다. 지폐를, 입장권을, 표를 확인할 때 어디 전화해서 확인하는 건 아니지 않은가? 만약 JWT를 받아 다른 서비스와 상호작용하여 제대로 발행된 건 맞는지, 소유자는 누구인지 등등 확인하는 일이 발생한다면, 기존의 쿠키-세션 방식과 별다른 차이가 없다.

     

    JWT토큰은 쿠키로도 보낼 수 있고, 헤더로도 보낼 수 있다. 헤더로 보낸다면 "Authorization: Bearer 토큰"처럼 될 것이다. 쿠키를 사용한다면 HttpOnly 옵션으로 쿠키를 보호하여 쿠키에 담긴 JWT의 보안을 챙길 수도 있다.

    세션

    세션은 서버쪽에서 클라이언트 관련 정보를 유지하는 것이다. 이 정보는 서버 안에서 파일로도 관리할 수 있고, 외부의 데이터베이스를 사용할 수도 있다. 쿠키 안에 세션 ID를 넣어 주고받는다. 클라이언트의 요청에 담긴 쿠키에서 세션 아이디를 추출하고, 그 ID를 바탕으로 서버는 유저 정보를 획득하여 다룬다.

    세션과 JWT 비교

    세션을 유저 확인으로 사용하는 경우, JWT를 유저의 신원을 증명하기 위한 용도로 사용하는 경우에 둘의 역할이 겹친다. 둘이 겹치는 프로세스는 다음과 같다.

    • 로그인 요청. 유저 ㅡ> 서버
    • 로그인 정보 확인후 로그인 과정 진행. 서버
    • 유저에게 응답. 서버 ㅡ> 유저
      • JWT는 토큰을 응답해줄 것이고, 세션은 세션 ID가 담긴 쿠키를 응답할 것이다.

     

    여기까진 세션과 JWT가 동일하고 이후부턴 다르다.

     

    세션이라면

    • 어떤 활동 요청(글쓰기, 수정 등). 유저 ㅡ> 서버
    • 서버는 쿠키에 담긴 세션 ID를 이용하여 유저를 식별하고, 어떤 글을 수정한다고 치면 수정을 할 수 있는지 권한 등을 확인하고 수정 진행. 서버
    • 결과 응답. 서버 ㅡ> 유저

    JWT라면

    • 어떤 활동 요청(글쓰기, 수정 등). 유저 ㅡ> 서버
    • 서버는 헤더나 쿠키에 담긴 JWT를 디코딩하고, 사인을 확인.
    • 페이로드에서 데이터를 뽑아 그대로 사용. 따라서, 페이로드에는 글을 쓰거나 수정할 수 있는 권한이 담겨 있어야 한다.
    • 결과 응답. 서버 ㅡ> 유저

    이중에 가장 문제가 될 수 있는 점은 JWT의 페이로드에서 글을 쓰거나 수정할 수 있는 권한이 담겨있는 것을 믿고 써야 하는 부분이다. 만약... 이것을 확인하기 위한 확인이 필요하면 세션이나 JWT나 차이가 없어진다.

     

    정리하자면, 세션-쿠키 방식은 서버사이드에서 인증 정보를 지니고 있는 셈이다. 서버의 메모리로 들고 있을 수도 있고, 데이터베이스로도 들고 있을 수 있다(stateful). 서버를 여러 대 운영한다면, 세션을 유지하기 위한 추가 처리가 필요하다.

     

    JWT방식은 클라이언트에서 인증 정보를 지니고 있는 셈이다. 서버가 늘어나도 상관없다. 서버에서 정보를 유지하지 않기 때문이다(stateless). 하지만, 탈취당했을 경우에 문제가 발생한다. 문제를 해결하기 위해 발급된 JWT를 취소하는 등의 관리를 하려면 서버에 정보를 유지해야 하고(stateful), 그때부터 세션-쿠키 방식과 다를 바가 없어진다.

    JWT를 어디에 저장하지?

    JWT를 어떻게 관리할 것인가를 논하는 아티클이 많다. 대개 비슷한 양상이면서도 다른 주장도 있었다. 내 생각엔 두 가지 정도로 분류할 수 있다.

     

    1. JWT를 쿠키에 저장하고 http only 옵션과 same site 옵션을 설정한다. http only 옵션으로 얻으려고 하는 것은 XSS를 방어하는 것. 왜? js로 접근할 수 없다. same site 옵션으로 얻을 수 있는 것은 CSRF 방어. 단점은 모든 요청마다 JWT가 담긴다는 것.

     

    2. JWT를 로컬스토리지에 저장하고 header에 포함하여 보낸다. 1번보다 XSS 방어에 취약하다. CSRF는 방어할 수 있다. 그런데, 꼭 JWT를 신경 쓰지 않더라도 웹 서비스에서 기본적으로 XSS를 방어하려고 하지 않나? 그러니까, JWT라고 유독 신경 쓰는 게 아니라 XSS에 웹 사이트 보안이 뚫리면, 전반적으로 심각한 문제인 것이다. 그래서, 굳이 XSS를 염려하며 JWT를 다루지 말고, 로컬스토리지에 저장하고, 헤더에 넣어 교환한다면, 간단하게 JWT를 처리할 수 있는 것이다.

    참고

    1. Stop using JWT for sessions
    2. How worried should I be about opening up a JWT to an XSS vulnerability?
    3. Why avoiding LocalStorage for tokens is the wrong solution
    4. Should JWT token be stored in a cookie, header or body

    댓글

Designed by Tistory.