JWT란?

2022-10-24

이번 포스트에서는 개발하다보면 항상 마주하는 JWT에 대해 다루어보려 한다.

JWT(JSON Web Token) 는 인증에 필요한 정보들을 암호화시킨 토큰이다.

JWT의 내부 구조는 세가지의 문자열의 조합이다. 실제 디코딩 되어있는 JWT 를 살펴보면 Header, Payload, Signature 로 이루어져 있다.



Header

{
  "alg": "HS256",
  "typ": "JWT"
}

typ은 토큰의 타입을 지정하고, alg는 signature부분에서 사용하는 토큰을 검증하기 위한 해싱 알고리즘을 지정한다.


Payload

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Payload 는 토큰에 담을 실제 정보가 들어있다. 여기에 담은 한 ‘조각’을 클레임(claim)이라고 부르며, 이는 name: value의 쌍으로 이루어져 있다.

클레임은 등록된(registered)클레임, 공개(public)클레임, 비공개(private)클레임 으로 크게 세 분류로 나뉘어져있다.

중요한 점은 payload에 민감한 정보를 담지 않아야 한다는 것 이다.

header와 payload는 json이 인코딩 되어있을 뿐이지 특별한 암호화가 걸려있는 것은 아니기 때문에 누구나 JWT를 디코딩하여 내부의 값을 확인 할 수 있기 때문이다.



jwt.io에서 서버에서 생성한 JWT를 넣으면 볼 수 있는 화면이다. JWT의 Header와 Payload는 특별한 암호화없이 base64 인코딩을 사용하기 때문에 누구나 디코딩 할 수 있으며, JWT에는 오로지 식별을 위한 정보만을 담아햐 한다.


Signature

HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);

Signature는 Header base64, Payload base 64 두가지의 인코딩 값을 더하고 SECRET_KEY (비밀키)로 해싱하여 생성한다.

위에서 설명했듯이 Header와 Payload는 base64로 단순 인코딩한 것이기 때문에 누구나 복호화하여 조작할 수 있지만, Signature는 서버측에서 관리하는 비밀키가 유출되지 않은 이상 복호화를 할 수는 없다.


세션 방식의 인증과 JWT인증의 차이

세션은 비밀번호와 같은 유저의 인증 정보를 서버측에 저장하고 관리한다.



1. 유저의 로그인 요청
2. 서버는 세션을 생성
3. 생성한 세션의 id를 클라이언트로 보냄
4. 응답받은 id를 클라이언트 브라우저에 저장
5. 인증이 필요할 때 id 값을 보낸다
6. 서버는 해당 id를 가지고 세션을 불러 유효성 검사 실시

세션방식의 인증은 서버측에서 유저들의 정보를 세션에 기억하고 있어야한다.

세션 기반 인증 방식은 세션 id를 가지고 유효성을 판별한다. 해커가 세션 id를 중간에 탈취한다면 매우 위험한 상황이 벌어질 것이다. 또, 서버에서 세션의 저장소를 사용하기 때문에 클라이언트에서 요청이 많아진다면 서버에 부하가 생길 수 있는 단점이 있다

이제 JWT 방식의 인증을 알아보자



1. 유저의 로그인 시도
2. 서버가 인증을 위한 정보를 시그니처를 추가한 토큰에 담아 생성 → JWT
3. AccessToken과 RefreshToken을 클라이언트로 보냄
4. 응답받은 Token을 클라이언트 브라우저에 저장
5. 인증이 필요할 때 해당 AccessToken을 서버로 보냄
6. 서버는 AccessToken을 가지고 유효성 검사

JWT를 기반으로 한 인증 시스템은 무상태성(stateless) 을 지닌다. 유저의 인증 정보를 서버나 세션에 담아두지 않기 때문에 클라이언트에서 요청이 많아도 서버에 부하를 일으키지 않는다.


JWT의 장점

1. 클라이언트의 인증 정보를 저장하는 세션과 다르게 무상태성(Stateless)을 지닌다.
2. 무상태성을 지니기 때문에 확장성이 있다.
3. 토큰을 사용한다면 어떤 디바이스에서든 토큰만 유효하다면 요청이 정상 처리된다.

JWT의 단점

1. JWT는 기본적으로 Payload에 대한 정보를 암호화 하지 않는다.
   BASE64로 인코딩만 하기 때문에 중간에 패킷을 가로채거나 다른 방법으로 토큰을 취득했다면
   디코딩을 통해 데이터를 볼 수 있다 그렇기 때문에 중요한 정보를 Payload에 넣지 말아야 한다.
2. claim에 넣는 데이터가 많아질 수록 JWT토큰이 길어진다.
   API호출 시에 매 호출마다 토큰을 서버에 전달해야 하는데
   토큰의 길이가 길다면 그만큼 네트워크 대역폭 낭비가 심할 수 있다.

Refresh Token ?

JWT는 탈취가 된다면 대처를 하기 어렵다. 그렇기 때문에 만료 기한을 설정하여 기간이 지나면 유효하지 않도록 한다. 발급받은 AccessToken의 만료기한이 다 되면 우리는 RefreshToken 을 사용한다

RefreshToken이란 AccessToken보다 만료 기한이 긴 토큰이다.

클라이언트가 요청을 보낼 떄 AccessToken의 기한이 만료 되었다면, RefreshToken을 이용하여 AccessToken의 재발급을 서버에게 요청한다. 서버는 RefreshToken이 유효하다면 AccessToken을 발급하여 다시 클라이언트에게 보내준다.



Reference

https://tech.toktokhan.dev/2021/04/30/JWT/

https://velog.io/@whitebear/쿠키-세션-토큰JWT-확실히-알고-가기

https://velopert.com/2350

© 2024 SongChangYeop All rights reserved