
- JSON 객체로, 주로 두 가지 정보를 포함한다.
- typ: 토큰의 타입(일반적으로 "JWT")
- alg: 서명에 사용된 해싱 알고리즘(예: HS256, RS256 등)
{
"alg": "HS256",
"typ": "JWT"
}
- 토큰의 타입과 서명에 사용할 알고리즘 정보를 명시하며, 이 정보는 토큰의 검증 및 해석에 사용된다.
Payload (페이로드)
- 토큰에 담길 실제 데이터(클레임, Claim)들이 들어있는 JSON 객체
- 클레임의 종류
- 등록된 클레임: JWT 표준에 정의된 예약된 클레임. (예: iss(발급자), exp(만료 시간), sub(주제), aud(대상자), iat(발급 시각) 등)
- 공개 클레임: 사용자 정의 클레임으로, 충돌 방지를 위해 URI 형식의 이름을 권장
- 비공개 클레임: 토큰을 사용하는 당사자 간에 정의한 임의의 정보(예: userId, role 등)
- 인증된 사용자 정보, 권한, 토큰의 유효기간 등 실제 서비스에서 필요한 정보를 담아 전달한다. 단, 페이로드는 Base64URL로 인코딩(암호화X)만 되어 있으므로, 민감한 정보는 넣지 않는 것이 원칙
- 패스워드 등 비밀 정보를 넣으면 절대 안 됨!
- 페이로드는 언제든 조작이 가능하다.
{
"sub": "1234567890",
"name": "John Doe",
"role": user,
"iat": 1516239022
}
- 여기서 role을 admin으로 변경하고 Base64 인코딩해 페이로드에 넣어주면 해당 토큰의 role을 admin으로 인식함
=> 위조를 방지하기 위해 signature (서명)이 필요!
Signature (서명)
- 헤더와 페이로드를 각각 Base64Url로 인코딩한 후, 헤더에서 명시한 알고리즘과 서버의 비밀키(혹은 개인키)로 서명한 값
signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
- 토큰의 무결성과 위변조 방지를 보장한다. 서명이 올바르지 않으면 토큰이 변조된 것으로 간주하여 인증에 실패
- 서버만이 비밀키를 알고 있으므로, 서명을 통해 토큰의 신뢰성을 검증할 수 있다.
검증 과정
1. 도착한 AccessToken의 헤더와 페이로드를 base64url로 인코딩한 뒤, 동일한 비밀키로 서명
2. AccessToken의 signature와 동일한지 확인
3. 동일하다면, 서버에서 발급한 토큰이 맞으므로 인증 / 다르다면 위조된 토큰이므로 거부
String base64UrlHeaderPayload = base64Url(header) + "." + base64Url(payload);
String expectedSignature = HMACSHA256(base64UrlHeaderPayload, secretKey);
if (!expectedSignature.equals(clientSignature)) {
throw new SecurityException("Invalid JWT: signature mismatch");
}
=> 이 과정을 통해 Payload가 바뀌었거나, 비밀키를 모르는 공격자가 만든 토큰인지를 판별할 수 있다.