Post

JWT

JWT

📌 JWT란?

JSON Web Token(JWT) 는 두 개체 간 JSON 객체를 사용하여 안전하게 정보를 전송하기 위한 표준이다.

‘인증’ 과정에서 JWT를 사용한다. 사용자가 로그인하면, 서버는 사용자의 정보와 권한을 담은 JWT를 발급한다. 이후 사용자는 JWT를 통해 자신을 증명하고, 서버는 JWT의 유효성만 검증하면 된다.

📌 구조

image.png

JWT는 ‘.’으로 구분된 세 부분으로 구성되며, 각 부분은 Base64URL 로 인코딩되어 있다.

1
2
3
4
{
  "alg": "HS256", // 서명 알고리즘
  "typ": "JWT"    // 토큰 타입
}

헤더에는 토큰의 종류와 서명에 사용된 알고리즘 정보를 담는다.

Payload

1
2
3
4
5
6
{
  "sub": "user123",
  "username": "senior.dev",
  "role": "ADMIN",
  "exp": 1672531199
}

페이로드에는 토큰에 담을 실제 정보인 claim 을 포함한다. 클레임이란 페이로드에 담는 각 정보를 말한다.

클레임에는 크게 세 가지 종류가 존재한다.

Registered Claim 은 표준으로 정의된 클레임이다. 필수는 아니며, 선택적으로 작성하면 된다.

클레임설명
iss토큰 발급자
sub토큰의 주체
aud토큰 수신자
exp토큰 만료 시간
iat토큰 발급 시간

Public Claim 은 충돌을 방지하기 위해 URI 형식으로 이름을 짓는 클레임이다.

Private Claim 은 서버와 클라이언트 간 협의하여 사용하는 클레임이다.

페이로드는 Base64URL로 인코딩될 뿐, 암호화된 것이 아니다. 따라서 누구나 디코딩하여 볼 수 있으므로 비밀번호와 같은 민감 정보는 담으면 안 된다.

signature

서명을 통해 토큰의 위조 여부, 발급자가 신뢰 가능한지 확인할 수 있다. 토큰의 무결성과 인증을 보장한다.

헤더와 페이로드는 Base64URL로 인코딩한 후, 두 문자열을 ‘.’으로 연결한다. 연결된 문자열을 헤더에 명시된 알고리즘(alg)와 서버의 비밀 키를 통해 암호화한다. 이렇게 구한 값이 서명이 된다.

📌 동작 과정

  1. 사용자가 로그인 요청을 보낸다.
  2. 서버는 사용자의 자격 증명을 확인하고, 성공 시 필요한 클레임을 담은 JWT를 생성하여 서명한다.
  3. 생성된 JWT를 클라이언트에 전달한다.
  4. 클라이언트는 JWT를 안전한 곳에 저장한다.
  5. 클라이언트는 보호된 API에 접근할 때마다 HTTP Authorization 헤더에 Bearer 스킴과 함께 JWT를 담아 보낸다.
  6. 서버는 헤더에서 JWT를 추출하여 검증한다.
  7. 검증을 통과하면 JWT의 페이로드에 담긴 사용자 정보를 신뢰하고 요청을 처리한다.

📌 장단점

가장 큰 장점은 서버가 상태를 관리하지 않게 되므로 수평적 확장에 유리해진다. 불필요한 DB 조회를 줄일 수 있으며, 다양한 도메인 간 안전하게 정보를 교환할 수 있다.

그러나 JWT는 유효기간 동안 유효하며, 만약 탈취되면 만료될 때까지 공격자가 사용할 수 있다. 이를 방지하게 위해 Access Token의 유효기간을 짧게 설정하고 Refresh Token으로 주기적으로 토큰을 재발급하도록 구현한다.

또한 로그아웃 등을 하게 되면 발급된 토큰을 무효화해야 하는데, JWT는 stateless이므로 서버에서 토큰을 강제로 무효화하기는 어렵다. 이를 해결하기 위해 별도의 Blacklist를 구현하여 로그아웃된 토큰을 Redis 등에 저장하여 확인하도록 구현한다.

📌 참고

https://ivory-room.tistory.com/88

This post is licensed under CC BY 4.0 by the author.