백엔드

JWT (JSON Web Token) 이해하기

do_hyuk 2024. 3. 27. 16:50

JWT 란?

JWT(JSON Web Token)은 약자대로 JSON 객체를 이용해서  토큰 자체에 여러 정보를 담을 수 있고 토큰을 이용해

인증 처리할 수 있는 것을 말한다.


JWT 구조

JWT 구조는 3가지로 분류할 수 있다.

 

header

header는 signature를 해싱하기 위한 알고리즘 정보를 담는 공간이다.

 

payload

payload는 서버와 클라이언트가 주고받을 수 있는 정보(시스템에 사용되는 정보)를 담을 수 있는 공간이다.

 

signature

signature는 해당 Token의 유효성을 검증하기 위한 정보 공간이다. 이 signature를 통해
해당 Token이 유효한지 체크하게 된다.


JWT 검증 방법

이제부터 JWT가 어떻게 해당 토큰이 유효한 것인지 알아보겠다.


eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzeWg4MDg4IiwiZXhwIjoxNjMzMTg0NDA4LCJpYXQiOjE2MzI1Nzk2MDh9.IO9BV

여기 예시로 만든 JWT 토큰이 있다. 이 토큰이 클라이언트로부터 서버 측에 값을 전달받았다고 가정해 보겠다.

서버 측은 이 토큰을 .으로 연결된 header, payload를 추출한다.

 

추출한 header, payload 값을 .으로 연결하고 동시에 header에 정의된 알고리즘 및 외부에 절대 노출해서는 안 되는

비밀키를 이용해 암호화하게 되고 base64로 인코딩한다.

 

서버에 저장된 비밀키를 이용해 암호화하여 만들어진 Signature 값과 클라이언트로부터 받은 Signature 값을 비교하게 되고

만약 틀리면 검증에 실패하게 되고 맞다면 검증에 성공하게 된다.


세션 및 쿠키와 JWT 서버 인증 방식 차이점

JWT를 활용해 서버 인증 방식을 자세히 알아보고 기존에 세션 방식과 무슨 차이점이 있는지 알아보겠다.

참고로 각각의 방식에 장점과 단점이 모두 존재한다.


세션 및 쿠키 이용한 인증 방식

세션 및 쿠키 인증 방식

세션과 쿠키의 차이는 여기를 참고

이미지를 보면 사용자로부터 로그인 정보를 받아 서버 측에서 인증 처리를 거쳐서 세션저장소에 session을 생성한다.

생성한 session에 대한 sessionID를 발급해 사용자 cookie에 저장한다.

 

이후 사용자가 어떤 요청을 보낼 때마다 헤더의 cookie에 sessionID를 담아서 전송한다.

서버는 사용자가 보낸 요청의 cookie에 감긴 sessionID와 세션저장소에 담긴 sessionID를 대조해 인증 상태를 판단한다.

(즉, 세션과 쿠키는 완전히 분리된 개념이 아니라 세션은 쿠키를 기반으로 되어있다.)

 

장점

세션 및 쿠키 방식은 기본적으로 쿠키를 매개로 인증을 거친다. 여기서 쿠키는 세션 저장소에 담긴 유저 정보를 얻기 위한

열쇠라고 보면 된다. 따라서 쿠키가 담긴 HTTP요청이 도중에 노출되더라도 쿠키 자체(세션 ID)는 유의미한 값을 갖고 있지 않다.

 (중요한 정보는 서버 세션에 있다.)

 

사용자 A는 1번, 사용자 B는 2번 이런 식으로 고유의 ID 값을 발급받기 때문에 서버에서는 쿠키 값을 받았을 때 일일이

회원정보를 확인할 필요 없이 바로 어떤 회원인지를 확인할 수 있어 서버 자원에 접근하기 용이하다.

 

문제점

하지만 이렇게 복잡한 과정을 거치더라도 완벽한 보안은 없다. 이미 인증된 사용자의 HTTP 요청을 해커가 가로챘다면

그 안의 쿠키도 탈취가 가능하다. 그래서 해커가 인증된 사용자의 쿠키를 실어 서버에 요청을 보내면 서버는

인증된 사용자인지 해커인지 구별할 방법이 없다.

 

해결법

HTTPS 사용, 서버와 클라이언트 간의 주고받는 정보를 암호화하여 요청을 탈취해도 정보를 읽을 수 없다.

세션에 유효시간을 지정한다.(일정 시간이 지나면 해당 클라이언트와 서버와의 세션을 끊는다.)


JWT 서버 인증 방식

JWT 서버 인증 방식

초기 로그인 정보를 인증하는 것까지는 세션 및 쿠키 방식과 같다. 사용자 인증 후 사용자 고유 ID 값을 부여한 후,

기타 정보와 함께 payload에 넣는다.

 

JWT의 유효기간을 설정한 후 암호화할 비밀키를 이용해 access token을 발급한다.

 

사용자는 access token을 받아 저장한 후, 인증이 필요한 요청마다 token을 헤더에 실어 보낸다.

세션 인증에서는 서버가 세션 ID를 저장하고 사용자가 쿠키에 실어 보낸세션 ID와 대조해서 확인하는 반면,

토큰을 사용하면 요청을 받은 서버는 토큰이 유효한지를 확인만 한다.

(세션 인증에 비해 서버 운영의 효율이 더 좋다.)

 

서버에서는 해당 token의 Signature를 비밀키로 복호화한 후, 조작여부, 유효기간을 확인한다.

검증이 완료되면, payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져온다.

 

장점

간편하다. JWT는 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요 없다.

이는 Stateless 한 서버를 만드는 입장에서는 큰 강점이다. 그렇기에 서버를 확장하거나 유지 보수하는데 유리하다.

(Stateless : 상태[쿠키/세션 정보]를 저장하지 않는 것)

 

확장성이 뛰어나다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능.
예를 들어 Facebook 로그인, Gogle 로그인 등은 모두 토큰을 기반으로 인증한다.

이에 선택적으로 이름이나 이미일 등을 받을 수 있는 권한도 추가할 수 있다.

 

문제점

이미 발급된 JWT에 대해서는 돌이킬 수 없다. 세션 및 쿠키의 경우 만일 쿠키가 악의적으로 이용된다면,

해당하는 세션을 지워버리면 된다. 하지만 JWT는 한번 발급되면 유효기간이 완료될 때까지 계속 사용이 가능.

따라서 악의적인 사용자는 유효기간이 지나기 전까지 정보를 털어갈 수 있다.

 

Payload의 정보가 제한적이다. Payload는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있다.

따라서 유저의 중요한 정보들은 Payload에 넣을 수 없다.

 

JWT의 길이. 세션 및 쿠키 방식에 비해 JWT의 길이는 길다.

따라서 인증이 필요한 요청이 많아질 수 록 서버의 자원 낭비가 발생한다.

 

해결법

기존의 access token의 유효기간을 짧게 하고 refresh token이라는 새로운 토큰을 발급한다.

그렇게 되면 access token을 탈취당해도 상대적으로 피해를 줄일 수 있다.

 

Refresh Token

Access Token(JWT)를 통한 인증 방식의 문제는 제삼자에게 탈취당할 경우 보안에 취약하다는 점이다.
유효기간이 짧은 Token의 경우 그만큼 사용자는 로그인을 자주 해서 새롭게 Token을 발급받아야 하므로 불편하다.
그러나 유효기간을 늘리자면, 토큰을 탈취당했을 때 보안에 더 취약해진다.


"그러면 유효기간을 짧게 하면서 더 좋은 방법은 없을까?"라는 고민에 의해 탄생하게 된 것이 Refresh Token이다.

 

Refresh Token은 Access Token과 똑같은 형태의 JWT이다.

처음에 로그인을 완료했을 때 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가지면서,

Access Token이 만료됐을 때 새로 발급해 주는 열쇠가 된다.

 

Access Token은 탈취당하면 정보가 유출되는 건 동일하다. 다만 유효기간이 짧기에 조금 더 안전하다는 뜻이다.

Refresh Token의 유효기간이 만료 됐다면, 사용자는 새로 로그인해야 한다.

Refresh Token도 탈취될 가능성이 있기 때문에 적절한 유효기간 설정이 필요하다.(보통 2주)

 

장점

기존의 Access Token만 있을 때 보다 안전하다.

 

문제점

구현이 복잡하다. 검증 프로세스가 길기 때문에 자연스럽게 구현하기 힘들어진다.(서버/클라이언트 모두)

 

Access Token이 만료될 때마다 새롭게 발급하는 과정에서 생기는  HTTP 요청 횟수가 많다.

이는 서버의 자원 낭비로 이어질 수 있다.


차이점

세션 및 쿠키 방식과 가장 큰 차이점은 세션 및 쿠키는 세션 저장소에 유저의 정보를 넣는 반면,

JWT는 토큰 안에 유저의 정보들을 넣는다는 점이다. 클라이언트 입장에서는 HTTP 헤더에 세션 ID나 토큰을 실어서

보내준다는 점에서는 동일하나, 서버 측에서는 인증을 위해 암호화를 하냐 별도의 저장소를 이용하냐의 차이가 발생한다.