[Security] JWT란?
이번 팀 프로젝트에서 인증을 맡게 되어 전반적인 인증 구조 설계와 더불어서 구성 요소에 대한 이해를 하려 한다. JWT(JSON WEB TOKEN) 필터를 구현하다가, 정작 JWT에 대한 이해도가 적다고 느껴져 기록한다.
JWT
JSON Web Token(이하 JWT)의 약자로 정보를 간결하고 안전하게 전송하기 위한 범용 텍스트 기반 메시징 형식이다. JWT는 모든 유형의 데이터에 대한 메시지로 사용될 수 있다.
JWT의 기본 구조
- JWT의 신원 정보를 담고 있는 payload
- header는 키/밸류 쌍으로 구성되어 있고 payload와 자신의 메시지에 메타데이터를 JSON 객체로 나타낸 것이다.
- payload는 JSON Claims 객체라고 불리고, 각각의 정보는 claim 이라고 부를 수 있고 신원에 대한 정보를 담고있다..
- JWT는 암호학적인 서명을 추가(JWS)하거나, 이것을 암호화(JWE)할 수 있다. JWS 또는 JWE 수신자는 서명을 검증하거나 복호화함으로써 신뢰할 수 있는 사람에게서 온 것을 높은 신뢰도로 확인할 수 있다.
- JWT는 최소한의 표현(기본적으로 Base64URL로 인코딩된 문자열)으로 압축될 수 있으므로 HTTP 헤더나 URL 등을 통해 전송할 수 있다.
JWT 예시
어떻게 압축되는지 한번 보자
- 초기 값
header
{
"alg": "none"
}
payload
the true sign of intelligence is not knowledge but imagination.
- 불필요한 공백 모두 제거
String header = '{"alg":"none"}'
String payload = 'The true sign of intelligence is not knowledge but imagination.'
2. 각각을 UTF-8 bytes 변환하고, Base64URL으로 인코딩
String encodedHeader = base64URLEncode( header.getBytes("UTF-8") )
String encodedPayload = base64URLEncode( payload.getBytes("UTF-8") )
3. 각각의 인코딩된 header와 claims 를 . 로 이어서 합친다.
String compact = encodedHeader + '.' + encodedPayload + '.'
- 최종적으로 연결된 compactJWT 문자열
eyJhbGciOiJub25lIn0.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.
이를 unprotected JWT라고 한다.
즉, JWT를 보호하는 디지털 서명이나 암호화가 없다.
JWS 예시
이번에는 Payload Object에 특정 신원에 대한 정보를 포함하는 JSON 클레임을 사용한다. 또한 JWT에 디지털 서명을 하여 제3자가 변경할 수 없도록 한다.
서버는 토큰을 받은 후, 같은 방식으로 Header와 Payload를 다시 계산한 다음, 기존 Signature와 비교하여 기존의 값이 변경되었는지 파악할 수 있다.
- 초기 값
이 경우에는 SHA-256을 사용하는 HMAC 알고리즘을 사용하여 jwt에 암호화 서명할 것을 header에 나타낸다. 또한 JSON 객체는 value를 갖는 단일 클레임을 가진다.
- 여기서 몇 개의 표준적인 Claim들이 있는데, sub도 그 중 하나이다.
header
{
"alg": "HS256"
}
payload
{
"sub": "Joe"
}
2~4.번은 상기 JWT 순번과 동일하다.
- 강력한 암호화 비밀키나, 서명 알고리즘과 동반한 개인 키를 선택하여, 4번의 문자열에 서명한다.(여기서는 concatenated)
SecretKey key = getMySecretKey()
byte[] signature = hmacSha256( concatenated, key )
5. signature은 항상 바이트 배열이므로 Base64URL로 인코딩만 진행 후 . 를 사용하여 문자열에 연결한다.
String compact = concatenated + '.' + base64URLEncode( signature )
이를 ‘JWS’라고 하는데 서명된 JWT의 줄임말이다.
JWE 예시
지금까지 unprotected JWT , protected JWT (JWS)에 대한 예시였다. 이 두 가지의 고유한 특징 중 하나는 그 안의 모든 정보를 누구나 볼 수 있다는 것이다. JWS는 데이터가 누군가에 의해 변경되지 않았는지 확인할 뿐, 누구도 볼 수 없도록 막지는 않는다.
민감한 정보로 간주되는 정보를 JWT로 표현하려면 완전히 암호화된 JWT, ‘JWE’가 필요하다. JWE는 암호화를 사용하여 페이로가 완전히 암호화 되고 인증된 상태를 유지하도록 한다. 특히 JWE는 데이터를 완전히 암호화하고 보호하기 위해 ‘AEAD’ 알고리즘을 사용하도록 요구한다.