JWT : JSON Web Token

DATE : 2023/11/12

JSON Web Token이란??

본격적인 설명에 앞서 JWT가 어떻게 생겼는지 먼저 확인해볼까 한다.

jwt.io로 접속하면 다음과 같은 페이지를 볼 수 있다.

왼쪽 Encoded 부분에 나오는 값이 우측에 있는 Decoded 내용으로 만들어진 JWT이다.

토큰 값을 가져와 자세히 보면

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ey
JleHAiOjE2OTk3NzAyOTksImlhdCI6MTY5OTc2O
TM5OSwidXNlciI6Imhhbmh4eCIsIm5hbWUiOiJo
YW4xMGh4eDE5In0.g8tVRdMDhgMSErfI_SKAaI0FBhCvBRNfnLE8WCdAO7s

dot으로 구분된 총 3개의 파트로 구성되어 있다.

이때 각각의 파트는

(1) header

(2) payload

(3) signature

로 최종 토큰은 단순히 base64URL encode된 값이 dot으로 연결되어 있는 형태라서

토큰으로 base64 decode를 진행해보면 위와 같이

header & payload 내용이 그대로 나오는 걸 확인할 수 있다.

header {
    "alg": "HS256",
    "typ": "JWT
}

JWT의 header에는 토큰과 관련된 metadata가 들어있다.

JWT라는 이름에서 알 수 있듯이 JSON object 형태의 값을 가지기 때문에

중괄호 내에

"key": "value"

형태로 데이터를 나열한다. 그 중에서도 "alg"은 algorithm을 의미하는 데

signature를 생성하는 과정에서 사용하는 알고리즘이 무엇인지 나타낸다.

[ payload ]

payload {
    "exp": 1699770299,
    "iat": 1699769399,
    "user": "hanhxx",
    "name": "han10hxx19"
}

payload에는 사용자와 관련된 실제 정보가 들어간다.

JWT에서는 payload에 들어있는 정보를 information 또는 claims라고 부른다.

위에서 확인 했듯이 토큰을 decode하기만 하면 payload 값은 그대로 노출되기 때문에

비밀번호와 같이 노출되면 안되는 정보는 포함하지 않는 것이 바람직하다.

참고로 KEY "exp"는 만기 일시를 의미하고 (= expire)

KEY "iat"는 토큰이 만들어진 일시를 뜻한다.

여기까지만 봤을 때는

header & payload에 base64URL encode만 해서 데이터를 보내는 것인데

만약 그 값이 중간에 조작되면 어떻게 하지? 라는 의문이 생긴다.

"base64 encode를 한다"는 건 반대로 토큰을 얻은 사람이 base64 decode를 하면

header & payload 값을 그대로 볼 수 있다는 의미이다.

만약 공격자가 중간에서 토큰을 조작한다면 우리는 이걸 확인할 방도가 필요하다.

이때 사용하는 값이 바로 signature이다.

[ signature ]

jwt.io에서 verify signature 부분을 자세히 보면 secret key를 적게 되어있는 걸 확인할 수 있다.

signature를 만드는 과정에서 필요한 재료 중 하나가 secret key라는 의미이다.

hash_function(base64UrlEncode(header)+"."+base64UrlEncode(payload), secret key)

header & payload를 각각 base64URL encode 처리를 한 후, dot으로 연결한 값과

secret key를 사용해 hash를 실행한 결과가 signature가 되는데

signature 값은

(1) secret key가 동일하지 않으면 절대 동일한 signature를 생성할 수 없으며

(2) 동일한 secret key를 사용하더라도 header or payload 값이 한 글자라도 달라지면

signature도 달라진다.

쉽게 말해 signature를 만들 때 사용하는 재료인 header, payload, secret key 중에서 하나라도

값이 달라져 버리면 동일한 signature를 만들 수 없다는 것이다.

이런 특성을 활용해 우리는 중간에 공격자가 토큰을 조작했는지 확인할 수 있게 된다.


만약 공격자가 중간에서 토큰을 가로채 payload 내용을 수정했다고 상상해보자!

토큰을 전달 받은 서버는 client가 보낸 토큰이 조작되었는지 확인하고 싶었다.

Server는 secret key를 알고 있기 때문에 직접 signature를 생성한 후

자신의 토큰에 있는 signature와 값이 동일한 지 비교하기로 했다.

토큰을 딱 받았을 때의 값은 base64 encode 되어있는 상태이기 때문에

header & payload 부분만 가져다가 secret key로

hash_function(base64_encoded header & payload, secret ket)

hash 함수를 실행한다.

Server는 hash_function의 결과로 signature 값을 하나 얻었고

이제 이 값을 토큰에 있는 signature와 비교하기만 하면 된다.

이때 signature (2)번 특성이 적용된다.

공격자는 payload의 값을 조작했을 뿐, secret key를 모르기 때문에 signature까지 조작하지는 못한다.

그렇기에 payload가 조작된 토큰으로 Server가 생성한 signature 값은

토큰에 포함된 signature (= 원래 payload 값으로 만들어진 signature)

와 절대 동일할 수가 없다.

이를 통해 Server는 토큰 값이 중간에서 조작됨을 인지할 수 있게 되는 것이다.

이와 같은 용도로 JWT의 마지막 파트에는 signature가 들어가게 된다.

Last updated