JWT algorithm: HS256, RS256

Jongho Jeon
Jongho’s Tech Blog
8 min readJun 29, 2021

OAuth 관련 포스팅을 몇 개 작성할 예정이다. 한 포스트에 OAuth의 모든 내용을 담으려니 내용이 너무 커져서, 작은 것들로 나눠서 하나씩 작성하려 한다. 첫 번째 내용은 JWT의 algorithm이다. 간단하게 HMAC SHA 해시 알고리즘과 RSA SHA 해시 알고리즘 2가지만 알아보자.

Introduction

아래 링크에서 손쉽게 JWT가 어떻게 생긴 것인지 확인할 수 있다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT는 base64 encoded string 3개가 점(.)으로 나눠진 토큰이다. (JSON Web Token)

Edit: JWT는 RFC7519에 정의된, 두 party 사이에전송되는 claim들을 표현하기위한 작고 URL-safe한 수단이다.

각 string은 순서대로 header, payload, verify signature(서명)이다. 오늘 이 포스트에서 알아볼 것은 JWT에 사용되는 알고리즘이므로, 그 부분에 집중하여 알아보자.

JWT header에는 alg라는 key에 알고리즘 이름이 저장되어 있다. 이를 통해 JWT가 어떤 알고리즘으로 hash 되어있는지 알 수 있다. JWT를 가지고 있는 클라이언트든 서버든 모두 확인할 수 있는 정보이다.

verify signature에는 이 header와 데이터를 저장하는 payload를 “특정 secret”으로 한 서명이 들어간다.

secret을 가지고 있는 서버에서는 같은 방식으로 secret을 hash하여 header 또는 payload가 위조,변조되지 않았는지 검증(verify)할 수 있다.

이제 우리는 JWT algorithm에 대하여 이야기하기 위한 준비가 되었다.

JWT Algorithm : HMAC vs RSA

각 알고리즘의 구체적인 내용은 이 포스트의 주제를 벗어난다. 이 포스트에서는 대칭과 비대칭 알고리즘이라는 차이에 대해서만 간단하게 다룰 것이다.

두 알고리즘 중 HMAC 암호화 방식은 대칭 키를 사용한다.

HMAC can provide message authentication using a shared secret instead of using digital signatures with asymmetric cryptography.

이와 반대로 RSA 암호화 방식은 비대칭 키(public key and private key)를 사용한다는 점이 HMAC와의 가장 큰 차이점이다.

RSA (Rivest–Shamir–Adleman) is a public-key cryptosystem.

In a public-key cryptosystem, the encryption key is public and distinct from the decryption key, which is kept secret (private).

RSA에서 public key는 message를 encrypt하는 데에 사용되고, 이 암호화된 값은 오직 private key를 통해서만 decrypt 될 수 있다.

public key can be known by everyone, and it is used for encrypting messages. The intention is that messages encrypted with the public key can only be decrypted in a reasonable amount of time by using the private key.

참고로, SHA는 해시 알고리즘이다. HS256과 RS256은 해시 알고리즘으로 SHA를 사용하는 것이다.

RSA: 잠깐, Public Key로 encrypt한다고?

RSA를 아주 간단하게 설명해보면, public key로 encrypt된 message는 오직 private key를 가진 주체만 message를 decrypt하여 plaintext를 얻을 수 있다고 말할 수 있다.

그런데, JWT는반대가 아닌가? JWT를 RSA algorithm으로 생성할 때 private key를 가진 주체만이 JWT를 생성할 수 있고, public key를 가진 모든 주체들은 JWT의 claim들을 읽을 수 있다. private key는 decrypt를 위한 수단인데 어떻게 JWT를 생성할 수 있는걸까?

같은 의문을 가진 질문을 아래 링크에서 확인할 수 있다.

Here, the private key is used for signing the tokens, and the public key is used for validating them.

우리가 JWT를 사용하면서 알아둬야 할 것은, JWT는 SSL 통신처럼 암호화된 값을 보내는 것이 아니라 서명(signature)을 하고 보낸다는 것이다. JWT를 사용하는 유저들(주로 서버)은 암호화 된 값을 복호화하여 평문을 얻어야 하는 것이 아니고, JWT의 header와 payload가 위변조되지 않은 값인지 검증(verify)만 하면 되는 것이다.

짧게 말해 암호화가 아닌 서명이기 때문에, 위에 나와있는 내용과 반대로 JWT에서 RSA는 private key를 sign 용도(encryption)로, public key를 verify 용도로 사용하고 있다.

JWK Spec을 보면 “use”라는 파라미터가 있는 것을 알 수 있는데, public key의 용도를 의미하는 것으로 sig(signature) 또는 enc(encryption)의 값을 가진다. (RFC7517) sig이면 public key는 signature를 verify하는 용도라는 의미이며 위에서 설명한 서명 방식이 이에 해당한다. (JWS vs JWE)

HMAC vs RSA 어느 것을 사용해야 하는가?에 대한 내용이 위 Stackoverflow 링크의 답변에 잘 설명되어 있다. 궁금하거나 고민하고 있다면 참고하길.

Experience

Apple은 Login 기능을 제공하기 위해 아래와 같은 public key endpoint을 제공한다.

https://appleid.apple.com/auth/keys

확인해보면 알 수 있듯이 하나가 아닌 여러 개의 key들을 제공하고 있다. 이 public key들을 통해 다른 유저들도 JWT를 verify할 수 있게 된다. (물론 JWT 생성은 못 한다)

JWT에서 RSA를 사용할 때의 장점은 이와 같이 하나의 엔드포인트에서 verify하기 위한 여러 가지 키들을 관리할 수 있다는 것이다. 반대로 HMAC와 같은 대칭 암호화를 사용한다면 하나의 엔드포인트에서 모든 secret들을 저장하는 것은 굉장히 위험한 일이다.

Infra에서 사용하는 envoy에서 JWT Validation 관련 설정을 할 일이 있었는데, (HMAC 대신 RSA를 사용함으로써) JWK를 사용하면 여러 서비스에 떠있는 envoy container들에 모두 동일하게 하나의 endpoint만 설정해주면 된다는 편의점이 있었다.

뭐니뭐니 해도, HMAC와 같은 대칭 키 암호화는 키 관리가 더 어렵고 취약하기 때문에 여러 서비스에서 JWT validation이 필요하다면 RSA를 선택하는 것이 현명한 판단일 것이다.

Conclusion

위 내용을 아주 간단하게 요약하면 결국 “JWT signature에 사용되는 알고리즘 중 HMAC는 대칭 암호화 방식이고, RSA는 비대칭 암호화 방식이다”라고 이해할 수 있다. 본 포스트에서는 관련 내용을 조금 더 자세하게 풀어 설명해보았다.

Reference

아래 문서는 Stateless server, scale out 관점 토큰 인증 방식의 필요성 등 JWT, JWK 관련 설명이 쉽게 잘 되어있다.

--

--