1. JWT
- 클라이언트와 서버, 서비스와 서비스 사이 통신 시 권한 인가(Authorization)를 위해 사용하는 토큰
- Bearer Authentication (JWT 혹은 OAuth에 대한 토큰을 사용하면 Bearer 타입 인증)
- 회원 인증과 정보 교류할 때 많이 사용합니다.
- 확장성이 좋아 토큰 기반 인증을 지원하는 다른 서비스에 접근할 수 있습니다.
- 사용자 인증에 필요한 모든 정보는 토큰 자체에 포함하기 때문에 별도의 인증 저장소(인증서버, DB, 세션 등)가 필요 없습니다.
- 담을 내용에 따라 크기가 커질 수 있고, 생성 비용이 많이 듭니다. (그러나 요즘 컴퓨팅 성능으로는 신경 쓰지 않아도 될 정도입니다.)
2. JWT 구조
- JWT는 .을 기준으로 헤더(Header) - 내용(Payload) - 서명(Signature)으로 구성되어있습니다.
- Json으로 되어있는 데이터를 Base64(Url Safe) Encode, Hmac 등을 이용하여 인코딩 후 .(dot)으로 구분하여 토큰 값을 만들어 냅니다.
- 아래의 사이트를 이용해 Base64 url encode, decode 확인해보세요.
Header.Payload.Signature
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNjM5OTg1NTg5LCJleHAiOjE2NDAwNzE5ODksInN1YiI6ImhlbGxvIEp3dCJ9.7q0elwhYCoHJUTS17HPqUBTwL8C2PsV57ME0-qU5hkM
Header Base64 Encode
Header
- 헤더는 토큰의 타입과 알고리즘(변조 방지를 위한)을 지정하는 정보를 포함합니다.
- Base64(Url Safe) Encode를 이용해 값을 생성합니다.
- 따라서 Base64 Decode를 하면 값을 확인할 수 있습니다.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
{"typ":"JWT","alg":"HS256"}
typ = 타입
alg = 사용한 알고리즘 ( HS256 = HMAC-SHA256 )
Payload
- 토큰에 담을 정보가 들어갑니다.
- 정보의 한 뭉치를 클레임(claim)이라고 합니다.
- claim은 key-value로 이루어져 있습니다.
- 클레임의 종류는 등록된 클레임, 공개 클레임, 비공개 클레임으로 나누어져 있습니다.
- Base64(Url Safe) Encode를 이용해 값을 생성합니다.
- 따라서 Base64 Decode를 하면 값을 확인할 수 있습니다.
eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNjM5OTg1NTg5LCJleHAiOjE2NDAwNzE5ODksInN1YiI6ImhlbGxvIEp3dCJ9
{"iss":"test","iat":1639985589,"exp":1640071989,"sub":"hello Jwt"}
iss = 발급자 (issuer)
iat = 토큰 발급 시간 (issued at)
exp = 토큰 만료 시간 (expiraton)
sub = 토큰 제목 (subject)
그 외에도
aud(대상), nbf(활성 일자), jti(고유식별자)가 존재하며
사용자 맘대로 key-value 형태로 저장할 수도 있습니다. -> 비공개 클레임
Claim
[등록된 (registered) 클레임]
등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기 위하여 이름이 이미 정해진 클레임들입니다.
iss = 발급자 (issuer)
iat = 토큰 발급 시간 (issued at)
exp = 토큰 만료 시간 (expiraton)
sub = 토큰 제목 (subject)
aud = 대상 (audience)
nbf = 활성 일자 (Not Before)
jti = 고유식별자, 중복적인 처리를 방지하기 위하여 사용, 따라서 일회용 토큰에 사용하면 유용합니다.
[공개 (public) 클레임]
공개 클레임들은 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 합니다. 충돌을 방지하기 위해서 클레임 이름을 URI 형식으로 생성합니다.
{"https://veneas.tistory.com/jwt_claims/auth_check":true}
[비공개 (private) 클레임]
양 측간에 협의하에 맘대로 key, value를 지정하여 사용하는 클레임입니다. 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용 시 유의해야 합니다.
{"name":"veneas"}
Signature
- Base64로 Encode 한 base64UrlEncode(header) + "." + base64UrlEncode(payload)를 지정한 암호화 알고리즘(Header에 지정됨)으로 인코딩하고 Base64(Url Safe) Encode하여 생성합니다.
- 변조 확인법은 위와 같은 방법으로 비밀키를 이용해 값을 생성해서 받은 값과 생성한 값을 비교하면 확인할 수 있습니다. (값이 다르면 변조된 값입니다.)
- 필자는 JWT 헤더에 HMAC-SHA256을 사용하겠다고 지정했습니다.
- https://veneas.tistory.com/entry/JAVA-%EC%9E%90%EB%B0%94-Hmac-%EC%95%94%ED%98%B8%ED%99%94-%ED%95%98%EA%B8%B0-HMAC-MD5-HMAC-SHA256-HMAC-SHA512
7q0elwhYCoHJUTS17HPqUBTwL8C2PsV57ME0-qU5hkM
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
secret키는 testPassword를 사용하여 값을 만들었습니다.
HMAC-SHA256(HeaderToken + "." + PayloadToken) + Base64 (Signature 대조하여 변조 확인)
- https://dinochiesa.github.io/hmachash/index.html 를 참고하여 해시값을 만들어봅시다.
- Base64 Url 값을 보면 같은 값이 생성된 것을 알 수 있습니다. 그렇다면 변조가 되지 않은 토큰 입니다.
[ HeaderToken + "." + PayloadToken ] -> HMAC-SHA256 + Base64 URL Encode
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNjM5OTg1NTg5LCJleHAiOjE2NDAwNzE5ODksInN1YiI6ImhlbGxvIEp3dCJ9
3. 정리
- JWT는 Header, Payload, Signature로 구성되어 있습니다.
- Header는 토큰 타입과 Signature를 만들 때 사용한 알고리즘 값을 가지고 있습니다.
- Payload는 토큰에 담을 정보들(Claim)이 들어갑니다.
- Header와 Payload 값은 Base64 Url Encode로 생성합니다.
- Signature는 Header와 Payload 그리고 Header에 지정된 알고리즘으로 생성하여 변조를 확인할 때 사용합니다.
'ETC' 카테고리의 다른 글
[Apache] 취약한 HTTP Method 제한 (httpd.conf) (0) | 2021.11.17 |
---|---|
[보안] 암호화와 복호화 그리고 암호 알고리즘 종류 (0) | 2021.08.06 |