JWT 서명 알고리즘 비교: HS256, RS256, ES256, EdDSA
2026년에 중요한 네 가지 JWT 서명 알고리즘의 트레이드오프, 각각이 키 배포에 어떤 의미인지, 그리고 실제 시스템에 여전히 나타나는 알고리즘 혼동 공격을 정리합니다.
JWT 헤더는 alg 필드를 담고, 거기서 선언하는 선택이 토큰을 어떻게
서명하는지, 소비자가 어떻게 검증하는지, 그 검증을 가능하게 하려면
어떤 인프라가 있어야 하는지를 결정합니다. IANA 레지스트리에는 수십
개의 알고리즘이 있지만, 실제로는 네 가지가 현실 시스템의 약 99%를
차지합니다. 이 글은 그 넷을 훑고, 운영상의 결과를 설명하며,
프로덕션 코드에 여전히 나타나는 알고리즘 혼동 공격으로 마무리합니다.
중요한 네 가지
| 알고리즘 | 계열 | 키 유형 | 서명 크기 | 어디서 보이는가 |
|---|---|---|---|---|
| HS256 | HMAC-SHA256 | 대칭(공유 비밀) | 32바이트 | 내부 서비스, 단순한 SaaS API |
| RS256 | RSA-PKCS1-SHA256 | 비대칭(RSA 2048+) | 256바이트 | Auth0, AWS Cognito 기본값, OIDC ID 토큰 |
| ES256 | ECDSA-P256-SHA256 | 비대칭(P-256) | 64바이트 | Apple, Google 서비스, 현대적 IdP |
| EdDSA | Ed25519 | 비대칭(Curve25519) | 64바이트 | OAuth GNAP, Solid 파드, 더 새로운 프로토콜 |
오래된 시스템에는 두 가지 알고리즘이 더 나타납니다. HS512(SHA-512 기반 HMAC으로, 출력 크기가 두 배인 점 외에는 HS256과 트레이드오프가 동일)와 RS512(RS256과 같은 주의 사항)입니다. IANA 레지스트리에는 PS256(RSA-PSS)도 올라 있는데, 암호학적으로는 PKCS1보다 낫지만 운영상 의 이득이 작고 생태계 지원이 더 들쭉날쭉해서 실제로는 거의 선택되지 않습니다.
HS256: 대칭 키가 합리적일 때
HS256은 하나의 공유 비밀로 토큰을 서명합니다. 토큰을 검증할 수 있는 사람은 새 토큰을 위조할 수도 있습니다. 이 제약은 발급자와 검증자가 같은 서비스일 때는 괜찮습니다. 예를 들어 하나의 바이너리가 세션을 발급하고 매 요청마다 검증하는 내부 API 토큰 서명이 그렇습니다. 하지만 토큰을 발행할 능력은 없으면서 검증만 해야 하는 제3자가 등장하는 순간 무너집니다.
HS256의 운영상 매력은 단순함입니다. 키는 시크릿 매니저에서 가져온 무작위 문자열 하나이고, 교체는 시크릿 한 번 갱신이며, 검증 연산은 해시 두 번과 상수 시간 비교입니다. 토큰은 작고(32바이트 서명) 처리가 빠릅니다(범용 하드웨어에서 1밀리초 미만).
트레이드오프는 키 배포입니다. 토큰을 검증해야 하는 모든 서비스가 서명 권한을 쥐게 됩니다. 단일 서비스라면 괜찮습니다. 세션 토큰을 검증할 수 있어야 하지만 그중 하나만 토큰을 발급할 수 있어야 하는 마이크로서비스 다섯 개라면, HS256은 잘못된 선택입니다. 나머지 넷도 비밀을 갖게 되고, 그중 어느 하나가 뚫리면 발급 자체가 뚫리는 것입니다.
RS256: 공개 키 기본값
RS256은 발급과 검증을 분리합니다. 발급자는 비공개 RSA 키를 쥐고, 짝이 되는 공개 키를 가진 누구든 토큰을 발행하지는 못한 채 검증할 수 있습니다. 이것이 OIDC를 가능하게 한 요소입니다. 신원 공급자(IdP)는 well-known JWKS URL에 공개 키를 게시하고, 임의의 신뢰 당사자(relying party)가 사전 조율 없이 ID 토큰을 검증합니다.
그 유연함에는 운영상의 복잡성이 따라옵니다. 키는 2048비트 이상이어야 합니다(AWS, Auth0, 대부분의 주요 IdP가 2048 또는 4096을 기본값으로 씁니다). 서명은 256바이트로 HS256의 여덟 배이고, 검증은 눈에 띄게 느립니다(마이크로초가 아니라 한 자리 밀리초). 50,000 RPS를 처리하는 서비스라면 RSA 검증의 CPU 비용이 플레임 그래프에 보입니다.
키 교체도 더 어렵습니다. 겹치는 기간 동안 옛 공개 키와 새 공개 키를 모두 담은 JWKS 엔드포인트를 게시하고, 새 토큰은 새 키로 서명하며, 가장 오래 사는 미만료 토큰이 만료된 뒤에야 옛 키를 제거합니다. 대부분의 JWT 라이브러리는 기본적으로 다중 키 JWKS를 읽을 수 있지만, 적지 않은 비율의 구현이 JWKS를 공격적으로 캐싱해 교체를 놓칩니다.
ES256: 더 짧은 키, 더 작은 서명, 같은 모델
ES256은 P-256 타원 곡선 위의 ECDSA를 씁니다. 암호학적 속성은 RS256과 같거나 더 강합니다. 256비트 ECC는 대략 3072비트 RSA의 보안을 제공합니다. 운영상의 이점은 상당합니다. 키는 256비트(32바이트), 서명은 64바이트로 RS256보다 네 배 작습니다. 검증이 더 빠릅니다. 서명도 더 빠르지만, IdP에서는 규모가 커질 때 검증 쪽이 중요합니다.
단점은 생태계 수준에 있습니다. ECDSA 구현은 역사적으로 RSA 구현보다 미묘한 버그가 더 많았고(소니 PS3의 ECDSA 논스 재사용, Java 15 EC_KEY 파서 CVE), 이를 완화하려면 라이브러리를 신중히 골라야 합니다. TLS 종단 장치와 HSM의 P-256 하드웨어 지원은 현대 인프라에서는 보편적이지만 오래된 장비에서는 더 들쭉날쭉합니다. 서명 자체는 결정적이지 않습니다. 무작위 논스가 바뀌므로, 검증 쪽은 같은 페이로드에 대해 서로 다른 서명이 나오는 것을 너그럽게 받아들여야 합니다.
새 서비스에 비대칭 알고리즘을 고르는 중이고 플랫폼이 지원한다면, ES256이 현대적 기본값입니다.
EdDSA: 가장 새로운 선택지
Ed25519를 쓰는 EdDSA는 가장 최근에 추가되었습니다. 결정적이고(같은 페이로드 → 같은 서명, 논스 의존 없음), 하드웨어 가속 없는 범용 CPU에서도 빠르며, ECDSA가 상수 시간 구현으로 막아야 하는 여러 부류의 부채널 공격에 면역입니다. RFC 8037이 2017년에 EdDSA를 JOSE에 추가했습니다.
라이브러리 지원은 따라잡았지만 아직 보편적이지는 않습니다. node-jose, PyJWT, 그리고 jose(가장 널리 쓰이는 JavaScript JWT 라이브러리)는 모두 지원하지만, 일부 엔터프라이즈 IdP와 SDK는 그렇지 않습니다. 현대적 스택을 겨냥한 신규 설계에는 EdDSA가 권장 선택지이고, 더 넓은 생태계와의 상호운용성을 위해서는 ES256이 여전히 더 안전한 선택입니다.
알고리즘 혼동 공격
실제 시스템에서 가장 심각한 JWT 취약점은 어떤 알고리즘에 있는 것이
아니라, alg 헤더를 신뢰하는 구현에 있습니다. 두 가지 공격 형태가
감사에서 여전히 나타납니다.
첫째는 alg=none입니다. JWS는 빈 서명을 가진 토큰을 만드는 "none"
알고리즘을 규정하는데, 서명이 불필요한 사용 사례를 위한 것입니다.
헤더를 디코딩하고 알고리즘을 조회한 뒤 "none"이 허용되는지 확인하지
않고 검증기로 넘기는 구현은 위조된 토큰을 기꺼이 검증해 버립니다.
해결책은 검증자 쪽에서 알고리즘 허용 목록(allow-list)을 명시적으로
유지하고 none을 의도적으로 제외하는 것입니다.
둘째는 RS256 → HS256 혼동입니다. RS256 토큰을 받도록 구성된 검증자는
발급자의 RSA 공개 키를 쥐고 있습니다. 공격자는 alg: HS256을
주장하는 새 토큰을 만들고, 그 공개 키를 공유 비밀인 양 써서
서명합니다. 순진한 구현은 헤더에 선언된 알고리즘에 대해 가진 키를
그대로 사용해, RSA 공개 키를 HMAC 키로 취급하고 위조를 받아들입니다.
해결책은 또다시 허용 목록입니다. 검증자 구성 시점에 알고리즘과 키
유형을 모두 고정(pin)하세요.
JWT 라이브러리를 통합할 때 던질 질문은 "RS256을 지원하는가"가 아니라
"검증자가 넘기기 전에 alg 필드를 내 허용 목록과 대조해 검증하는가"
입니다. 주요 라이브러리(jose, jsonwebtoken, PyJWT, node-jose)는 검증
호출에서 알고리즘을 명시적으로 고정하도록 발전해 왔지만, 오래된 코드
경로나 자체 구현은 여전히 가끔 이를 건너뜁니다.
새 서비스를 위한 선택
발급자와 검증자가 같은 바이너리인 내부 전용 API라면 HS256으로 충분하고 가장 단순한 선택입니다. 제3자 검증이 필요한 경우에는 비대칭이 필수입니다. 플랫폼이 깔끔하게 지원하면 ES256, 신규 현대적 스택이라면 EdDSA, 레거시 시스템과의 최대 상호운용성을 원하면 RS256입니다.
무엇을 고르든, 검증자 쪽에서 알고리즘을 고정하고, 합리적인 캐싱 헤더와 함께 안정적인 JWKS URL에 공개 키 자료를 게시하며, 필요해지기 전에 키 교체 훈련을 위한 여유를 잡아 두세요. 현장에서 토큰을 들여다볼 때는 JWT Decoder가 검증을 시도하지 않고 헤더와 페이로드를 보여 줍니다. 검증자의 비밀 없이 인증 흐름을 디버깅할 때 유용합니다.