JWT는 3개의 필드로 구성되어 있다.
각각의 필드에 대해서 알아보자.
Header
{
"typ" : "JWT",
"alg" : "HS512"
}
Header는 두 가지로 구성되어 있다.
typ (Type)
해당 토큰의 타입을 나타낸다.
위 예시에서는 JWT를 토큰으로 사용한다는 의미이다.
alg (Algorithm)
서명 생성을 위해 사용하는 해시 알고리즘이 무엇인지 나타낸다.
일반적으로 SHA-2(HS256), SHA-256(RS256) 알고리즘을 주로 사용한다.
Payload
{
"sub": "1",
"iss": "ori",
"exp": 1669897918,
"iat": 1636987918
}
사용자와 토큰에 대한 속성값(property)를 key-value 형태로 저장하는데 이를 Claim이라고 한다.
Claim은 토큰에서 사용할 정보의 조각이라고 보면 된다.
JWT 표준 필드(Registered Claim Names)
Registered된 Claim들은 토큰의 생성과 소멸, 토큰 식별과 대상에 관한 정보를 포함하고 있으며, key는 3글자로 된다.
1. iss (Issuer) : 토큰 발급자
2. sub (Subject) : 토큰 제목 - 사용자에 대한 식별 값
3. aud (Audience) : 토큰 대상자
4. exp (Expiration Time) : 토큰 만료 시간
5. nbf (Not Before) : 토큰 활성 날짜
6. iat (Issued At) : 토큰 발급 시간
7. jti (JWT Id) : JWT 토큰 식별자(발급자가 여러명일 때 이를 구분하기 위한 값)
사용자 지정 클레임 (Custom claims)
위 표준 필드 말고도 개발자가 직접 키, 쌍을 정의할 수 있는데, 이를 사용자 지정 클레임이라고 한다.
예를 들어, 애플리케이션 내부에서 일반 사용자와 관리자를 나누기 위한 클레임을 정의한다면
{
...
"roles" : "admin"
...
}
{
...
"roles" : "user"
...
}
다음과 같이 사용하여 구분할 수 있다.
공개 클레임과 비공개 클레임
사용자 지정 클레임 중에서도 정형화된 틀이 존재하는데, 이런 클레임들을 공개 클레임이라고 한다.
정형화된 클레임의 예시로는 [유저 닉네임], [지역], [이메일], [성별], [생일] 등이 있다.
위 예시는 roles라는 공개 클레임을 이용했다.
클레임 정리 링크
위 주소에 들어가면 사용되는 클레임의 이름과 설명이 나열되어 있다.
비공개 클레임 이와 반대로 은 애플리케이션 내에서만 사용하는 특별한 클레임이다.
다만, JWT는 일반적으로 암호화되지 않은 형태로 전송되므로, 민감한 정보는 담아두면 안된다.
Signature
시그니처는 해당 토큰이 유효한 토큰인지 검사한다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 : 헤더의 JSON 값을 base 64 인코딩한 값
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFpbXlvbiIsImlhdCI6MTUxNjIzOTAyMn0 : Payload의 JSON 값을 base64로 인코딩한 값
en2SNsw3FX52UJPAfwHDwzQy31kINnuMahbR5zFH5hU : Header + Payload 문자열을 암호화하고 base 64로 인코딩한 값
토큰 생성에 사용된 base64는 암호화가 아니라 인코딩이기 때문에 디코딩만으로 쉽게 확인할 수 있다.
토큰 값
결과
결과를 잘 보면, {"sub":"1234567890","name":"Aimyon","iat":1516239022} 다음 문자열이 이상해보인다.
분명 signature 부분도 base64로 인코딩이 되었다고 하는데, 어째서 제대로 된 값이 나오지 않는 걸까?
사실 이 결과는 잘 출력된 결과이다.
왜냐하면, Signature 값은 암호화된 채로 base64 인코딩 됐기 때문이다.
따라서 위에서 보이는 이상한 문자열은 암호화된 문자열이다.
signature의 암호화 방법
평문을 암호화/복호화 하기 위해선, 암호화/복호화에 사용되는 키 값이 필요하다.
이런 키를 비밀 키 라고 한다.
- signature 생성 방법
- 서버는 암호화를 위한 비밀 키가 존재한다.
- 헤더의 정보 + 페이로드의 정보를 비밀키로 암호화한다.(복호화를 위해선 비밀키가 필요하다)
- 생성된 암호화 코드를 base64로 인코딩한다
- 인코딩된 코드를 signature 부분에 추가한다.
- 확인 흐름
- 서버는 클라이언트로부터 토큰을 받는다.
- 서버는 토큰 값의 sigature 부분을 비밀키로 복호화한다.
- 복호화결과, 복호화한 Header, payload 값과 토큰의 Header, payload부분이 일치하는지 확인한다.
- 일치한다면 요청을 처리하고, 일치하지 않는다면 요청을 거부한다.
정리하자면, 암호화된 서명은 헤더정보 + 페이로드 정보를 담고 있으며, 토큰의 위조 여부를 확인하기 위해
[복호화된 헤더 정보와 페이로드 정보]를 [토큰 값으로 전송된 헤더정보 + 페이로드 정보]와 일치하는 지 확인하는 것이다.
출처
이번에야말로 JWT를 파헤쳐보자
JSON 위키백과
JWT(JSON Web Token에 대해서..)
JWT(Json Web Token)알아가기
'개발 지식' 카테고리의 다른 글
JWT를 이용한 로그아웃 구현 (1) | 2024.02.28 |
---|