- JSON Web Token은 compact claims representation format으로 HTTP의 Authorization header나 URI query parameter와 같은 제약된 공간에서 사용하기 적합하다.
- JWT는 JSON object로 전송될 claim들을 encoding한다.
JWT 구조
HEADER.PAYLOAD.SIGNATURE
- asdfadQ3FadfaAdNtqh.fq1egYajaRfjG.ADGYadfhg12asdFda 뭐 이런식으로 점으로 이어져있다.
-
Header
- JWT를 검증하는데 필요한 정보를 가진 객체
- Signature에 사용한 암호화 알고리즘이 무엇인지, Key의 ID가 무엇인지 정보를 담음.
- 이 정보를 Json으로 변환해서 UTF-8로 인코딩한 뒤 Base64 URL-Safe로 인코딩한 값이 들어가 있다.
-
결과 값이 난해한 문자로 보이지만 암호화된 값은 아님.
{
"alg": "HS512",
"kid": "key1"
}
-> 요게 막 인코딩되서 바뀐것일 뿐임.
-
Payload
- 인증에 필요한 데이터
- 이 데이터들의 각각 필드들을 Claim 이라고 말한다.
- 대부분의 경우 Claim에 username을 포함.
- 인증할 때 payload에 있는 username을 가져와서 유저 정보 조회시 사용
- 또한 토큰 발행시간(iat)와 토큰 만료시간(exp)을 포함.
- 그 외에도 원하는 Claim을 얼마든지 추가 가능하지만 민감정보는 포함x.
- Payload 역시 인코딩될 뿐 암호화되지 않는다.
{
"sub" : "user",
"iat" : 3021636970,
"exp" : 3024637570,
}
-> 인코딩.
-
Signature
- Header와 Payload는 누구나 만들 수 있는 데이터
- 따라서 저 두개만으로는 토큰의 진위여부를 판단할 수 없다.
- 그래서 JWT의 구조에서 가장 마지막에 있는 Signature는 토큰 자체 진위여부를 판단하는 용도로 사용됨.
- Signature는 Header와 Payload를 합친 뒤 비밀키로 Hash를 생성하여 암호화함.
- 헤더, 페이로드 값을 SecretKey로 Hashing하고 Base64로 변경함.
- HS512 + Secret Key
- 전달받은 토큰의 헤더와 페이로드를 시크릿키와 결합해서 해싱했을 때 이 Signature 값과 동일한지 체크하는 것 같다.
- 따라서 secret key 유출될시 큰일난다.
Key Rolling
- secret key가 유출되면 모든 데이터가 유출될 수 있기 때문에 이런 문제를 방지하기 위해서 secret key를 여러개 두고 Key 노출에 대비.
- Key Rolling이란 Secret Key를 여러개 사용하고 수시로 추가하고 삭제해줘서 변경하여, SecretKey 중에 1개가 노출되어도 다른 Secret Key와 데이터를 안전하게 지키는 방법.
- Secret Key 1개에 Unique한 ID를 연결시켜 둔다.
- JWT 토큰을 만들 떄 헤더에 kid를 포함하여 제공하고 서버에서 토큰을 해석할 때 kid로 Secret Key를 찾아서 Signature를 검증함.
참고
RFC 7519 - JSON Web Token (JWT)
Spring Boot Authorization Tutorial: Secure an API (Java)
Java에서 JJWT(Java JSON Web Token)를 이용한 JWT(JSON Web Token) 사용방법