Logo Logo
GitHub Designed by Logto

JSON 웹 서명 (JWS)이란 무엇인가요?

JSON 웹 서명 (JWS)은 JSON 형식으로 데이터를 서명하고 검증하는 표준 방법을 정의합니다. 이는 전송된 데이터의 무결성과 신뢰성을 보장하기 위해 현대적인 애플리케이션과 OpenID Connect (OIDC) 와 같은 개방형 표준에서 널리 사용됩니다.

JWS는 특히 JSON 웹 토큰 (JWT) 과 작업할 때 유용합니다. 예를 들어, ID 토큰 (ID token) 이나 액세스 토큰 을 JWS로 서명하고 수신자가 추가로 네트워크 요청을 하지 않고 검증할 수 있습니다.

JWS는 어떻게 작동하나요?

JWS는 암호화 알고리즘을 사용하여 데이터를 서명하고 서명을 생성합니다. JWS에는 두 가지 주요 개념이 있습니다: JWS 헤더와 JWS 직렬화.

JWS 헤더

JWS는 서명 알고리즘과 키 관리에 대한 중요한 메타데이터를 포함하는 헤더를 가집니다. JWS 헤더의 일반적인 속성은 다음과 같습니다:

  • alg (Algorithm): 데이터를 서명하는 데 사용되는 암호화 알고리즘.
  • typ (Type): 토큰의 유형, 예를 들어 JWT.
  • kid (Key ID): 데이터를 서명하는 데 사용된 키의 고유 식별자.
  • jku (JWK Set URL): JSON Web Key Set (JWKS) 이 위치한 URL.

JWS 헤더 속성에 대한 자세한 목록은 JOSE Header 를 참조하세요.

JWS 직렬화

JWS에는 두 가지 직렬화 형식이 있습니다: compact과 JSON입니다. 각 형식은 서명된 데이터를 표현하는 자체 방법을 가지고 있습니다.

Compact 직렬화

Compact 직렬화에서는 JWS가 점 (.)으로 구분된 세 개의 Base64URL로 인코딩된 부분으로 나타납니다. 세 부분은 다음과 같습니다:

{{header}}.{{payload}}.{{signature}}

각 부분은 특정 목적을 가집니다:

  • header: Base64URL로 인코딩된 서명 알고리즘과 키 관리에 대한 메타데이터.
  • payload: Base64URL로 인코딩된 서명된 데이터.
  • signature: 헤더와 페이로드의 암호화 서명.

[!Note] Compact 직렬화에는 보호되지 않은 헤더가 포함되지 않습니다.

예를 들어, JWS는 다음과 같이 보일 수 있습니다:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0.Xv9da66g3y4nxs_0hlR9CBkOG9GkxfPmq1_7u4tNeXE

Base64URL로 인코딩된 부분을 디코딩하면 JWS는 다음으로 구성됩니다:

  • Header: {"alg":"HS256","typ":"JWT"}
  • Payload: {"sub":"1234567890","name":"Alice"}
  • Signature: Xv9da66g3y4nxs_0hlR9CBkOG9GkxfPmq1_7u4tNeXE

헤더는 JWS가 HMAC-SHA256 알고리즘 (HS256)을 사용하여 서명되었으며, 토큰의 유형이 JWT (typ: "JWT")임을 JSON 형식으로 지정합니다. 페이로드는 사용자에 대한 기본 정보를 포함하며, 예를 들어, 주체 (sub)와 이름 (name)을 포함합니다.

서명은 다음을 통해 계산됩니다:

Hash(
  Base64URLEncode(header) || '.' || Base64URLEncode(payload),
  secret
)

JWS 헤더에 따르면 Hash 함수에서 HMAC-SHA256 알고리즘이 사용되며, 이 경우 secret은 공유 비밀 키 top-secret입니다.

JWT와 JWS가 작동하는 자세한 예시는 서명 키 (Signing key) 문서를 참조하세요.

JSON 직렬화

JSON 직렬화는 JWS를 표현하는 더 구조화된 방법을 제공합니다. JWS는 다음 속성을 가진 JSON 객체로 표현됩니다:

{
  "payload": "{{payload}}",
  "signatures": [
    {
      "protected": "{{protected-header}}",
      "header": "{{header}}",
      "signature": "{{signature}}"
    }
  ]
}
  • payload: Base64URL로 인코딩된 페이로드. 이것이 서명된 데이터입니다.

  • signatures: 각 보호된 헤더, 헤더, 및 서명을 포함하는 서명 객체의 배열.

    각 서명 객체는 다음을 포함할 수 있습니다:

    • protected: Base64URL로 인코딩된 보호된 헤더 (compact 직렬화의 header).
    • header: JSON 형식의 보호되지 않은 헤더. 이 헤더는 서명에 포함되지 않습니다.
    • signature: 헤더와 페이로드의 암호화 서명 (compact 직렬화의 signature).

예를 들어, JSON 직렬화의 JWS는 다음과 같이 보일 수 있습니다:

{
  "payload": "eyJzdWIiOiIx...bGciOiJIUzI1NiJ9",
  "signatures": [
    {
      "protected": "eyJhbGci...InR5cCI6IkpXVCJ9",
      "header": {
        "kid": "2010-12-29"
      },
      "signature": "Xv9da66g3y4nxs...R9CBkOG9GkxfPmq1_7u4tNeXE"
    },
    {
      "protected": "eyJhbGci...InR5cCI6IkpXVCJ9",
      "header": {
        "kid": "2010-12-30"
      },
      "signature": "Yv9da66g3y4nxs...R9CBkOG9GkxfPmq1_7u4tNeXE"
    }
  ]
}

위의 예에서는 동일한 페이로드에 대해 두 개의 서명 (signatures 배열)이 있습니다. 각 서명 객체는 보호된 헤더, 헤더, 및 서명을 포함합니다.

참고