웹 서비스를 만들 때 구현해야 하는 것 중 하나는 인증이다.
이전에는 서버에 저장하는 세션/쿠키 방식을 사용했지만, 최근에는 토큰을 이용한 인증 방식을 많이 사용한다. 토큰을 이용한 인증 방식 중 하나가 JWT(Json Web Token)
이다.
JWT는 JSON 형태로 되어 있는 웹 토큰이다.
JWT는 서버에 토큰 정보를 저장하지 않는다. 서버는 해당 토큰이 유효한지만 체크한다.
JWT = 머리(Header) + 페이로드(Payload) + 서명(Signature)
Header
Header은 JWT를 어떻게 검증(Verify) 하는가에 대한 정보를 담고 있다.
( 서명에 사용하는 암호화 방식에 대한 정보 )
{
"alg" : "HS256", // 서명 시 사용하는 알고리즘
"kid" : "key ID" // 서명 시 사용하는 키
}
위의 JSON 객체를 문자로 직렬화하고 인코딩을 하여 헤더를 생성한다.
Base64URLSafe(UTF-8('{"alg": "ES256","kid": "Key ID"}'))
Paload
JWT의 실제 내용이 담겨진다.
각 속성들을 클라임 셋(Claim Set)이라 부르며 토큰 생성자, 생성 일시 등에 대한 값들로 구성한다.
토큰의 유효기간 검사를 위해 토큰 발생 시점에 대한 속성을 생성한다.
{
"iss": "miniddo",
"iat": "1586364327"
}
Base64URLSafe('{"iss": "miniddo","iat": "1586364327"}')
Signature
암호화하여 위조를 방지한다.
점(.)을 구분자로 Header와 Payload를 합친 문자열을 서명한 값이다.
key 값이 필요하다. 내용은 같지만, key 값에 따라 다른 결과가 나온다.
Base64URLSafe(Sign('ES256', '${PRIVATE_KEY}', 'Header값.Payload값')))
JWT
점(.)을 구분자로 Header, Payload, Signature을 합치면 JWT가 완성된다.
Header값.Payload값.Signature값
header = '{"alg":"HS256", "kid" : "key ID", "typ":"JWT"}';
payload = '{"iss": "miniddo", "iat": "1586364327"}';
// 암호화에 사용될 key 값
key = 'antsecretkey';
// 암호화된 서명을 만들어 내기 위한 부분, 앞서 말한대로 header 와 payload 를 합친다. unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload);
signature = HMAC-SHA256(key, unsignedToken);
// 다 만들어졌으니 세 부분을 모두 합친다.
token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature);
이렇게 만들어진 토큰은 Header의 alg, kid 속성과 공개 키를 이용해 검증한다.
서명 검증이 완료되면 JWT의 모든 내용을 신뢰하고 Payload 값으로 원하는 처리를 한다.