JWT 서명

JWT 서명 (JWS, RFC 7515)

JWS(JSON Web Signature)는 JSON 기반 데이터 구조의 콘텐츠를 암호학적으로 서명하거나 MAC 처리해서 무결성과 보안을 제공하는 표준이에요. JWT와 JWS는 사실 같은 계열의 스펙이라서, 'JWT'라고 부르는 토큰의 대부분은 내부적으로 JWS 형식을 따라요.

JWS는 세 부분으로 이뤄져요. JOSE 헤더( protected header), JWS 페이로드, 서명인데, 이들이 점(.)으로 구분된 연속된 base64url 구조로 직렬화돼요. algorithm 헤더 파라미터로 어떤 서명 알고리즘을 쓸지 정합니다.

출처: https://www.rfc-editor.org/rfc/rfc7515.txt

JWS 구조

JWS에서 핵심은 세 가지가 점(.)으로 연결된 형태예요.

BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
  • protected headeralg, typ 같은 메타데이터를 담는 JOSE 헤더예요.
  • payload — 서명할 실제 콘텐츠(JWT의 클레임들)예요. base64url로 인코딩돼요.
  • signature — 헤더와 페이로드base64url을 연결한 값을 alg가 지정한 알고리즘으로 서명한 결과예요.

JOSE 헤더

헤더 안의 alg(algorithm) 파라미터는 반드시 있어야 해요. 서명 검증 시 alg가 금지된 none이나 부적절한 알고리즘으로 바뀌는 알고리즘 혼동(algorithm confusion) 공격을 막으려면, 수신자는 서버가 허용한 알고리즘 목록과 alg를 대조하고 서명 검증 전에 반드시 확인해야 해요.

대표적인 alg 값은 아래와 같아요.

  • HS256 / HS384 / HS512 — HMAC with SHA-2, 대칭 키(비밀) 기반
  • RS256 / RS384 / RS512 — RSASSA-PKCS1-v1_5 with SHA-2, 비대칭 키 기반
  • ES256 / ES384 / ES512 — ECDSA with P-256/P-384/P-521 and SHA-2
  • PS256 / PS384 / PS512 — RSASSA-PSS with SHA-2
  • EdDSA — Edwards-curve Digital Signature Algorithm (Ed25519 등)
  • none — 서명 없음. 반드시 명시적으로 허용된 경우에만 사용해야 해요.

서명 생성과 검증

생성 과정은 이렇게 정리할 수 있어요.

  1. alg를 포함한 protected header와 payload를 각각 base64url로 인코딩해요.
  2. 발신자 서명 입력 = ASCII(BASE64URL(header) || '.' || BASE64URL(payload))를 구성해요.
  3. alg가 지정한 서명 알고리즘으로 입력을 서명해서 JWS Signature를 만들어요.

수신자는 같은 입력에 대해 공개키나 비밀 키로 검증해요. 검증이 성공하면 페이로드를 base64url 디코딩해서 JWT 클레임을 읽을 수 있어요.

검증 시 주의점

  • 페이로드를 신뢰하기 전에 항상 서명을 먼저 검증해야 해요.
  • alg는 반드시 서버의 허용 목록과 일치하는지 확인하고, none이나 예상 밖의 알고리즘은 거부해야 해요.
  • base64url 디코딩 시 패딩(=)과 문자 집합 변환 오류를 방지하기 위해 구현 라이브러리를 쓰는 게 안전해요.

더 알아보기