1. JWT의 의미와 구성
JWT란 Json Web Token의 약자로 사용자 인증에 사용되는 토큰이다. JWT의 구조는 다음과 같이 Header, Payload, Signature로 이루어진다.
1.1. Header
첫 번째로 Header는 typ과 alg 두 가지 정보로 구성된다. typ은 토큰의 타입을 말한다. 우리는 JWT를 사용하므로 현재 typ은 JWT가 된다. alg는 Signature를 해싱하기 위한 알고리즘을 말한다. RSA, SHA 256 등이 있다. 즉, 아래와 같이 작성된다.
{
"alg": "HS256",
"typ": "JWT"
}
1.2. Payload
두 번째로 Payload는 토큰의 정보가 들어있다. 이때 이 정보들 하나하나 각각을 Claim이라고 부른다. (Key-Value 한 쌍이 하나의 Claim이다.) Claim의 종류는 Registered, Public, Private로 총 세 개가 있다. 단, header와 payload는 json이 base64로 인코딩되어 있는 것으로 특별한 암호화가 된 것이 아니다. 따라서 누구나 디코딩을 하면 header와 payload를 알 수 있기 때문에 payload에 민감한 정보를 넣어서는 안된다.
1.2.1. Registered Claim
Registered Claim은 토큰에 대한 정보를 담기 위해 이름들이 미리 정해진 claim들이다. 단, 필수는 아니고 선택하여 사용하면 된다. 아래와 같은 것들이 있다.
- iss (issuer): 토큰 발급자
- sub (subject): 토큰 제목
- aud (audience): 토큰 대상자
- exp (expiration): 토큰 만료 시간
- isa (issued at): 토큰 발급 시간
- nbf (not before): 토큰 활성 날짜 (날짜가 지나기 전에 토큰이 처리되지 않음)
- jti (jwt id): JWT 식별자 (중복처리 방지, 일회용 토큰 등에 사용)
1.2.2. Public Claim
Public Claim은 사용자 마음대로 사용할 수 있다. 하지만 충돌 방지를 위해 URI 형식으로 키를 지정한다. 즉, 아래와 같이 작성할 수 있다.
{
"https://example.com/jwt/client": true
}
특정 JWT 관련 정보들은 굳이 URI로 작성하지 않고 아래 URI에서 정의된 키값을 사용해도 된다.
1.2.3. Private Claim
서버와 클라이언트(통신을 주고 받는 것들) 간에 협의하여 임의로 지정한 정보를 말한다. 이름이 충돌될 수 있으므로 주의해야 한다. 아래와 같이 사용할 수 있다.
{
"token_type": "access"
}
1.3. Signature
Signature는 Header와 Payload의 인코딩 값을 합치고 헤더에서 정의한 알고리즘을 통해 암호화한다. 그리고 이 값을 다시 Base 64로 인코딩한 것이 Signature다. 이때 암호화에서 사용되는 키는 서버에서 가지고 있는 개인키이다. 따라서 Signature는 서버에서만 복호화가 가능하다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
2. JWT의 동작 원리 및 장단점
클라이언트가 서버로 로그인을 하면 서버는 JWT 토큰을 발급해준다. 이후 클라이언트는 요청을 보낼 때 해당 토큰과 함께 보낸다. 이때 이러한 토큰은 탈취당하기 쉽다. 따라서 만료 시간을 보통 짧게 준다.
이러한 JWT 방식은 토큰만 있으면 다른 서버에 요청해도 인증이 가능하기 때문에 확장성이 용이하다. 이외에도 다음과 같은 장점들이 있다.
- 데이터 위변조 방지
- 서버는 Stateless 상태 (세션은 서버가 Stateful)
단, 아래와 같은 단점도 존재한다.
- payload가 총 세 가지 claim을 담고 있는데 이 payload가 길어질 수록 토큰의 길이도 길어진다. (네트워크 부하가 심해짐.)
- payload는 암호화되지 않았기 때문에 중요한 정보를 담으면 안된다.
- 서버가 토큰을 저장하지 않기 때문에 토큰이 탈취된 경우 대처가 힘들다.
위와 같은 단점을 최소화 하기 위해 2가지 방법이 고안되었다.
- 토큰의 유효 기간을 짧게 한다.
- 이 방식은 토큰이 금방 만료된다. 따라서 사용자가 로그인을 자주해야 한다는 말이 되므로 사용자에게 불편하다. - Refresh Token을 사용한다.
- 서버는 클라이언트에게 유효기간이 짧은 Access Token을 준다. 그리고 Access Token을 재발급하기 위한 토큰인 Refresh Token도 제공한다. 이 토큰의 경우 DB에 저장되게 된다. 사용자가 Access Token의 유효 기간이 만료되면 Refresh Token으로 재발급 받으면 되기 때문에 기존 방식보다 로그인 주기가 길다.
- 하지만 서버의 DB에 Refresh Token을 저장한다는 점에서 완전히 Stateless하다고 볼 수 없다.
출처
1. JWT 구조 사진: https://velopert.com/2389
'BackEnd > Spring' 카테고리의 다른 글
[Spring MVC-2] 예외 처리 (0) | 2024.06.27 |
---|---|
[Spring MVC-2] 로그인 - 필터, 인터셉터 (0) | 2024.05.27 |
[Spring MVC-2] 로그인 - 쿠키, 세션 (0) | 2024.05.27 |
[Spring MVC-2] Bean Validation (0) | 2024.05.24 |
[Spring MVC-2] Validation (0) | 2024.05.23 |