Internet Engineering Task Force (IETF) A. Backman, Editor
Request for Comments: 9421 Amazon
Category: Standards Track J. Richer, Editor
ISSN: 2070-1721 Bespoke Engineering
M. Sporny
Digital Bazaar
2024년 2월

HTTP 메시지 서명


초록

이 문서는 HTTP 메시지의 구성요소에 대해 디지털 서명 또는 메시지 인증 코드(MAC)를 생성, 인코딩 및 검증하는 메커니즘을 설명합니다. 이 메커니즘은 서명자가 전체 HTTP 메시지를 알지 못하거나 메시지가 검증자에게 도달하기 전에 중간자에 의해 변환될 수 있는 사용 사례를 지원합니다. 또한 이 문서는 진행 중인 HTTP 교환에서 이후의 HTTP 메시지에 서명을 적용하도록 요청하는 수단을 설명합니다.

이 메모의 상태

이 문서는 Internet Standards Track 문서입니다.

이 문서는 Internet Engineering Task Force (IETF)의 산물입니다. 이는 IETF 커뮤니티의 합의를 나타내며, 공개 검토를 거쳐 Internet Engineering Steering Group (IESG)에 의해 출판 승인을 받았습니다. 인터넷 표준에 관한 추가 정보는 RFC 7841의 섹션 2에서 확인할 수 있습니다.

이 문서의 현재 상태, 오류 정정(errata), 및 피드백 제공 방법에 대한 정보는 https://www.rfc-editor.org/info/rfc9421에서 얻을 수 있습니다.

Copyright Notice

Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.


1. 소개

메시지 무결성 및 진위성은 많은 HTTP 애플리케이션의 안전한 운영에 필수적인 보안 속성입니다. 애플리케이션 개발자는 일반적으로 TLS 위에서 애플리케이션을 운영함으로써 전송 계층이 이러한 속성을 제공해 주기를 기대합니다 [TLS]. 그러나 TLS는 단일 TLS 연결에 대해서만 이러한 속성을 보장하며, 클라이언트와 애플리케이션 간의 경로가 여러 독립적인 TLS 연결로 구성될 수 있는 경우(예: 애플리케이션이 TLS 종료 게이트웨이 뒤에 호스팅되는 경우 또는 클라이언트가 TLS 검사 장치 뒤에 있는 경우)에는 TLS가 클라이언트와 애플리케이션 간의 종단간 메시지 무결성이나 진위성을 보장할 수 없습니다. 또한 일부 운영 환경에서는 TLS 사용이 실용적이지 않거나(예: 브라우저의 클라이언트 인증서 제시) 메시지 진위성 제공에 필요한 기능을 사용할 수 없게 하는 장애물이 존재할 수 있습니다. 더 나아가 일부 애플리케이션은 TLS 인증서와는 별도로 HTTP 메시지에 상위 수준의 애플리케이션 전용 키를 바인딩해야 할 필요가 있습니다. 결과적으로 TLS는 많은 HTTP 기반 애플리케이션의 메시지 무결성과 진위성 요구를 충족시킬 수 있지만 만능 해결책은 아닙니다.

또한 많은 애플리케이션은 서명 또는 검증 시점에 서명자에게 와이어 상의 HTTP 메시지 전체가 완전하게 보이지 않는 상황에서도 서명을 생성하고 검증할 수 있어야 합니다. 이는 라이브러리, 프록시 또는 애플리케이션 프레임워크가 메시지의 일부를 변경하거나 숨기기 때문에 발생합니다. 이러한 애플리케이션은 계층화와 추상화를 위반하지 않고 애플리케이션에 가장 중요한 메시지 부분을 보호할 수 있는 수단이 필요합니다.

마지막으로 JSON Web Signature와 같은 객체 기반 서명 메커니즘은 서명된 정확한 정보가 온전하게 전달되는 것을 요구합니다 [JWS]. 이러한 기술을 HTTP 메시지에 적용할 때, HTTP 메시지의 요소는 객체 페이로드에 직접 혹은 해시 포함을 통해 복제되어야 합니다. 이 관행은 서명을 검증할 때 반복된 정보를 일관되게 확인해야 하기 때문에 복잡성을 도입합니다.

이 문서는 HTTP 메시지 구성요소에 대해 분리된(detached) 서명을 사용하여 종단간 무결성과 진위성을 제공하는 메커니즘을 정의합니다. 이 메커니즘은 애플리케이션이 의미 있고 적절한 메시지 구성요소만을 선택하여 디지털 서명 또는 MAC를 생성할 수 있게 합니다. 엄격한 정규화 규칙은 메시지가 HTTP에서 허용되는 여러 방식으로 변형되었더라도 검증자가 서명을 검증할 수 있도록 보장합니다.

이 문서에서 설명하는 서명 메커니즘은 세 부분으로 구성됩니다:

  • 서명 베이스를 생성하기 위해 사용되는 다양한 프로토콜 요소 및 기타 HTTP 메시지 구성요소에 대한 공통 명명법 및 정규화 규칙 집합(섹션 2).
  • 암호 원시를 적용하여 이 서명 베이스를 통해 HTTP 메시지 구성요소에 대한 서명을 생성하고 검증하는 알고리즘(섹션 3).
  • 서명 및 관련 메타데이터를 HTTP 메시지에 첨부하고, HTTP 메시지에서 첨부된 서명과 메타데이터를 파싱하는 메커니즘. 이를 위해 이 문서는 "Signature-Input" 및 "Signature" 필드를 정의합니다 (섹션 4).

이 문서는 또한 "Accept-Signature" 필드를 통해 후속 하나 이상의 메시지에서 서명 사용을 협상하는 메커니즘을 제공합니다(섹션 5). 이 선택적 협상 메커니즘은 양측이 기회주의적이거나 애플리케이션 주도의 메시지 서명과 함께 사용할 수 있습니다.

이 문서에서 정의한 메커니즘은 애플리케이션을 위한 전체 보안 메커니즘을 구성하는 데 유용한 도구입니다. 이 도구 키트는 강력한 기능을 제공하지만 전체 보안 이야기를 완성하기에는 충분하지 않습니다. 특히 섹션 1.4에 나열된 요구사항과 섹션 7에서 논의된 보안 고려사항은 이 명세의 모든 구현자에게 매우 중요합니다. 예를 들어, 이 명세는 HTTP 메시지 콘텐츠(HTTP 섹션 6.4)를 직접적으로 커버하는 수단을 정의하지 않습니다; 대신 이 문서는 메시지 콘텐츠의 해시를 제공하기 위해 Digest 명세 [DIGEST]를 활용합니다(참조: 섹션 7.2.8).

1.1. 관습 및 용어

이 문서에서 단어 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 및 "OPTIONAL"은 BCP 14 [RFC2119][RFC8174] 에 설명된 대로, 그리고 모두 대문자로 나타날 때에만 그렇게 해석되어야 합니다.

"HTTP 메시지", "HTTP 요청", "HTTP 응답", "대상 URI", "게이트웨이", "헤더 필드", "중계자", "요청 대상", "트레일러 필드", "발신자", "메서드", 및 "수신자"라는 용어는 [HTTP]에 정의된 대로 사용됩니다.

간결함을 위해 이 문서에서는 "서명"이라는 용어를 디지털 서명(비대칭 암호를 사용하는 경우)과 키드 MAC(대칭 암호를 사용하는 경우) 모두를 지칭하는 데 사용합니다. 유사하게 동사 "sign"은 특정 서명 베이스에 대해 디지털 서명 또는 키드 MAC 중 어느 하나를 생성하는 것을 의미합니다. "디지털 서명"이라는 한정 용어는 비대칭 암호 서명 연산의 출력을 구체적으로 지칭합니다.

이 문서는 데이터 유형을 지정하기 위해 RFC8941 섹션 3에서 사용하는 용어를 사용합니다: List, Inner List, Dictionary, Item, String, Integer, Byte Sequence, 및 Boolean.

이 문서는 ABNF를 사용하여 여러 문자열 구조를 정의하며 다음 ABNF 규칙을 사용합니다: VCHAR, SP, DQUOTE, 및 LF. 또한 [STRUCTURED-FIELDS]의 규칙인 sf-string, inner-list, 및 parameters를 사용합니다. 그리고 [HTTP][HTTP/1.1]field-content, obs-fold, 및 obs-text 규칙을 사용합니다.

위에 열거된 것들 외에, 이 문서는 다음 용어들을 사용합니다:

HTTP Message Signature:
하나 이상의 HTTP 메시지 부분을 포함하는 디지털 서명 또는 키드 MAC. 특정 HTTP 메시지는 여러 개의 HTTP 메시지 서명을 포함할 수 있습니다.
Signer:
HTTP 메시지 서명을 생성하거나 생성한 엔티티. 여러 엔티티가 서명자로 동작하고 동일한 HTTP 메시지에 별도의 서명을 적용할 수 있습니다.
Verifier:
HTTP 메시지에 대해 HTTP 메시지 서명의 검증을 수행하거나 수행한 엔티티. 하나의 HTTP 메시지 서명은 여러 번, 잠재적으로 다른 엔티티에 의해 검증될 수 있습니다.
HTTP Message Component:
HTTP 메시지의 일부로, HTTP 메시지 서명에 의해 포함될 수 있는 부분.
Derived Component:
지정된 알고리즘 또는 절차를 사용하여 HTTP 메시지로부터 유도된 HTTP 메시지 구성요소. 섹션 2.2 참조.
HTTP Message Component Name:
필드 이름이나 유도된 구성요소 이름과 같이 HTTP 메시지 구성요소의 출처를 식별하는 문자열.
HTTP Message Component Identifier:
HTTP 메시지 구성요소 이름과 모든 매개변수의 조합. 이 조합은 특정 HTTP 메시지 서명 및 해당 서명이 적용되는 HTTP 메시지에 대해 특정 HTTP 메시지 구성요소를 고유하게 식별합니다.
HTTP Message Component Value:
특정 HTTP 메시지 맥락에서 주어진 구성요소 식별자에 연관된 값. 구성요소 값은 HTTP 메시지에서 유도되며 일반적으로 정규화 과정을 거칩니다.
Covered Components:
필드(섹션 2.1) 및 유도된 구성요소(섹션 2.2)에 대한 HTTP 메시지 구성요소 식별자의 순서화된 집합으로, 서명에 의해 포함되는 메시지 구성요소 세트를 나타냅니다. 이 집합은 @signature-params 식별자 자체를 포함하지 않습니다. 이 집합의 순서는 보존되어 서명자와 검증자 사이에 전달되어 서명 베이스의 재구성을 용이하게 합니다.
Signature Base:
서명자와 검증자가 Covered Components 집합과 HTTP 메시지를 사용하여 생성하는 바이트 시퀀스입니다. 서명 베이스는 암호 알고리즘에 의해 처리되어 HTTP 메시지 서명을 생성하거나 검증합니다.
HTTP Message Signature Algorithm:
서명과 검증 과정을 설명하는 암호 알고리즘으로, HTTP_SIGNHTTP_VERIFY 원시를 기준으로 정의되며, 섹션 3.3에 설명되어 있습니다.
Key Material:
서명을 생성하거나 검증하는 데 필요한 키 자료. 키 자료는 종종 명시적 키 식별자와 함께 식별되어 서명자가 어떤 키를 사용했는지 검증자에게 알릴 수 있습니다.
Creation Time:
서명이 생성된 시점을 나타내는 타임스탬프로, 서명자가 주장하는 시간.
Expiration Time:
서명이 더 이상 검증자에 의해 수용되어서는 안 되는 시점을 나타내는 타임스탬프로, 서명자가 주장하는 시간.
Target Message:
HTTP 메시지 서명이 적용되는 대상 HTTP 메시지.
Signature Context:
HTTP 메시지 구성요소 값이 추출되는 데이터 소스. 이 문맥에는 대상 메시지와 서명자 또는 검증자가 가질 수 있는 추가 정보(예: 요청의 전체 대상 URI 또는 응답에 관련된 요청 메시지)가 포함될 수 있습니다.

"UNIX timestamp"라는 용어는 [POSIX.1]의 섹션 4.16이 부르는 "Epoch 이후의 초(second since the Epoch)"를 의미합니다.

이 문서에는 부분적 및 전체 HTTP 메시지의 비규범적 예시가 포함되어 있습니다. 일부 예시는 긴 값에 대해 줄 바꿈을 표시하기 위해 단일 역슬래시(\)를 사용합니다(참조: [RFC8792]). 줄 바꿈에 사용된 \ 문자와 래핑된 줄의 선행 공백은 값의 일부가 아닙니다.

1.2. 요구사항

HTTP는 중계자가 다양한 방식으로 메시지를 변환하는 것을 허용하며 때로는 요구합니다. 이로 인해 수신자가 원래 전송된 메시지와 비트 단위로 동일하지 않은 메시지를 받을 수 있습니다. 이런 경우 수신자는 발신자의 HTTP 메시지의 원시 바이트에 대한 무결성 보호를 검증할 수 없습니다. 디지털 서명이나 MAC를 검증하려면 서명자와 검증자가 동일한 서명 베이스를 가져야 하기 때문입니다. 메시지의 정확한 원시 바이트를 서명 베이스의 신뢰할 수 있는 소스로 간주할 수 없으므로, 서명자와 검증자는 각각의 메시지 버전에서 의미를 변경하지 않는 안전한 변경에 견고한 메커니즘을 통해 독립적으로 서명 베이스를 생성해야 합니다.

어떤 변경이 안전한 변경인지 또는 안전하지 않은 변경인지 엄격히 정의하는 것은 여러 이유로 현실적이지 않습니다. 애플리케이션은 다양한 방식으로 HTTP를 사용하고 특정 메시지의 일부(예: 메시지 콘텐츠, 메서드, 특정 헤더 필드)가 관련성이 있는지에 대해 의견이 다를 수 있습니다. 따라서 범용 솔루션은 서명자가 어떤 메시지 구성요소를 서명할지에 대해 어느 정도 제어할 수 있어야 합니다.

HTTP 애플리케이션은 브라우저의 JavaScript 환경처럼 HTTP 메시지에 대한 완전한 접근이나 제어를 제공하지 않는 환경에서 실행되거나, 프로토콜 세부를 추상화하는 라이브러리(예: Java HTTP Client (HttpClient) 라이브러리)를 사용할 수 있습니다. 이러한 애플리케이션은 HTTP 메시지에 대한 지식이 불완전하더라도 서명을 생성하고 검증할 수 있어야 합니다.

1.3. HTTP 메시지 변환

앞서 언급한 것처럼, HTTP는 구현체가 다양한 방식으로 메시지를 변환하도록 명시적으로 허용하며, 일부 경우에는 요구합니다. 구현체는 이러한 많은 변환을 견딜 수 있어야 합니다. 다음은 HTTP 하에서 발생할 수 있는 변환의 비규범적이고 완전하지 않은 목록으로, 문맥을 제공하기 위해 제시합니다:

  • 서로 다른 필드 이름을 가진 필드들의 순서 재배열(RFC9110 섹션 5.3).
  • 같은 필드 이름을 가진 필드들의 결합(RFC9110 섹션 5.2).
  • Connection 헤더 필드에 나열된 필드의 제거(RFC9110 섹션 7.6.1).
  • 제어 옵션을 나타내는 필드의 추가(RFC9110 섹션 7.6.1).
  • 전송 코딩의 추가 또는 제거(RFC9110 섹션 7.7).
  • Via(RFC9110 섹션 7.6.3) 및 Forwarded(RFC7239 섹션 4)와 같은 필드의 추가.
  • HTTP의 다른 버전 간 변환(예: HTTP/1.x에서 HTTP/2로 또는 그 반대).
  • 필드 이름, 요청 URI 스킴 또는 호스트와 같은 대소문자를 구별하지 않는 구성요소의 대소문자 변경(예: "Origin" → "origin").
  • 요청 대상과 권한이 함께 적용될 때 대상 URI에 변화가 생기지 않는 방식으로의 변경(참조: RFC9110 섹션 7.1).

또한 일부 변환은 사용 중단되었거나 허용되지 않지만 실제 환경에서 여전히 발생할 수 있습니다. 이러한 변환도 서명을 깨뜨리지 않고 처리될 수 있습니다. 예로는 다음과 같은 작업이 포함됩니다:

  • 필드 값에서의 선행 또는 후행 공백의 사용, 추가 또는 제거.
  • 필드 값에서의 obs-fold 사용, 추가 또는 제거(RFC9112 섹션 5.2).

이러한 유형의 변환은 서명에 의해 포함된 메시지 구성요소에 대해 수행되더라도 서명 검증을 방해해서는 안 된다고 간주됩니다. 또한 서명에 포함되지 않은 구성요소에 대한 모든 변경은 서명 검증을 방해해서는 안 됩니다.

이러한 종류의 변환 예시와 그것이 메시지 서명에 미치는 영향은 부록 B.4에서 찾을 수 있습니다.

반면에, 유도된 구성요소의 값을 변경하거나 포함된 구성요소의 필드 값들을 파싱하고 재직렬화하는 것과 같은 다른 변환은 서명이 대상 메시지에 대해 더 이상 유효하지 않게 만들 수 있습니다. 이 명세를 적용하는 애플리케이션은 기대되는 변환이 Covered Components의 선택으로 적절히 처리되는지 주의해야 합니다.

1.4. HTTP 메시지 서명의 적용

HTTP 메시지 서명은 다양한 상황과 애플리케이션에 적용할 수 있는 범용 도구로 설계되었습니다. HTTP 메시지 서명을 적절하고 안전하게 적용하려면, 애플리케이션 또는 이 명세의 프로필은 최소한 다음 항목들을 명시해야 합니다:

  • Covered Components 목록(섹션 2) 및 요구되거나 기대되는 서명 매개변수(섹션 2.3)의 집합. 예를 들어, 인증 프로토콜은 Authorization 필드를 포함하도록 요구하여 인증 자격 증명을 보호하고 서명 매개변수에 created 매개변수(섹션 2.3)를 포함하도록 요구할 수 있습니다. 반면에 의미상 관련된 HTTP 메시지 콘텐츠를 기대하는 API는 [DIGEST]에 정의된 Content-Digest 필드의 존재 및 포함을 요구하고, API 고유의 tag 매개변수 값을 요구할 수도 있습니다.
  • 필수 또는 기대되는 Covered Component 필드나 매개변수의 예상된 Structured Field 타입([STRUCTURED-FIELDS]).
  • 서명을 검증하는 데 사용될 키 재료를 검색하는 수단. 애플리케이션은 일반적으로 서명 매개변수(섹션 2.3)의 keyid 매개변수를 사용하고, 그로부터 키를 해석하는 규칙을 정의하지만, 적절한 키가 서명자의 키 사전 등록과 같은 다른 수단으로 알려져 있을 수도 있습니다.
  • 서명자가 사용하고 검증자가 수용할 허용 가능한 서명 알고리즘의 집합.
  • 검증자가 서명 검증에 사용된 서명 알고리즘이 키 재료와 메시지 문맥에 적합한지 결정하는 수단. 예를 들어 서명 매개변수의 alg 매개변수를 사용하여 알고리즘을 명시적으로 명시하거나, 키 재료로부터 알고리즘을 유도하거나, 서명자와 검증자가 합의한 사전 구성된 알고리즘을 사용할 수 있습니다.
  • 주어진 서명에 사용된 키와 알고리즘이 메시지 문맥에 적합한지 결정하는 수단. 예를 들어 ECDSA 서명만 기대하는 서버는 RSA 서명을 거부해야 한다는 것을 알아야 하고, 비대칭 암호만 기대하는 서버는 대칭 암호를 거부해야 합니다.
  • HTTP 메시지와 그 애플리케이션 문맥으로부터 메시지 구성요소를 유도할 문맥을 결정하는 수단. 일반적으로 이것은 대상 HTTP 메시지 자체이지만, 문맥은 외부 호스트명과 같은 구성으로 애플리케이션이 알고 있는 추가 정보를 포함할 수 있습니다.
  • 섹션 2.4에 제공된 메커니즘을 사용하여 요청과 응답 간 바인딩을 필요로 하는 경우, 그러한 바인딩의 속성을 제공하는 데 필요한 요청 메시지 및 응답 메시지의 모든 요소.
  • 서명이 유효하지 않거나 키 재료가 부적절하거나 유효 시간 창이 명세를 벗어나거나 구성요소 값을 계산할 수 없거나 서명 검증 과정 중 기타 오류가 발생할 때 검증자가 서명자에게 반환하는 오류 메시지와 코드. 예를 들어 서명이 인증 메커니즘으로 사용되는 경우 HTTP 상태 코드 401(Unauthorized) 또는 403(Forbidden)이 적절할 수 있습니다. HTTP API의 응답이라면 400(Bad Request)과 같은 상태 코드와 함께 [RFC7807], [RFC9457]와 같은 문제 세부 정보를 포함하여 잘못된 키 재료 사용을 나타낼 수 있습니다.

이러한 매개변수를 선택할 때, 애플리케이션의 검증자가 서명 베이스를 재생성하는 데 필요한 모든 정보에 접근할 수 있어야 한다는 점을 보장해야 합니다. 예를 들어 리버스 프록시 뒤의 서버는 리버스 프록시가 변경한 것처럼 보이는 경우에도 유도된 구성요소 @target-uri를 사용하려면 원래 요청 URI를 알아야 합니다(참조: 섹션 7.4.3). 또한 응답에 서명을 사용하는 애플리케이션은 클라이언트가 서버가 req ("request-response") 매개변수를 사용하여 서명한 요청의 모든 서명된 부분에 접근할 수 있도록 해야 합니다 (섹션 2.4).

이러한 유형의 프로파일링에 대한 세부 사항은 애플리케이션의 권한 범위에 속하며 이 명세의 범위를 벗어납니다. 그러나 몇 가지 추가 고려사항이 섹션 7에서 논의됩니다. 특히 필수 구성요소 식별자 집합을 선택할 때 적용 범위가 애플리케이션에 충분한지 확인하는 주의가 필요합니다(참조: 섹션 7.2.1섹션 7.2.8). 이 명세는 애플리케이션을 위한 전체 보안 시스템의 일부만을 정의합니다. HTTP 메시지 서명을 기반으로 전체 보안 시스템을 구축할 때는 해당 시스템 전체에 대한 보안 분석을 수행하는 것이 중요합니다. AWS Signature Version 4와 같은 역사적 시스템([AWS-SIGv4])은 유사한 메커니즘을 애플리케이션에 적용하는 예시와 영감을 제공할 수 있지만, 이런 과거 시스템의 검토가 HTTP 메시지 서명 적용에 대한 보안 분석의 필요성을 면제하지는 않습니다.


2. HTTP 메시지 구성요소

서명자와 검증자가 어떤 구성요소가 서명에 포함되는지 확인할 수 있도록, 이 문서는 HTTP 메시지 서명이 포함하는 구성요소들에 대한 구성요소 식별자, 이러한 구성요소 식별자와 연관된 값을 HTTP 메시지에서 유도하고 정규화하는 규칙 집합, 그리고 이러한 정규화된 값들을 서명 베이스로 결합하는 수단을 정의합니다.

이 값들을 유도하기 위한 서명 문맥은 메시지의 서명자와 검증자 모두가 접근할 수 있어야 MUST 합니다. 또한 같은 서명 안의 모든 구성요소에 대해 문맥이 동일해야 MUST 합니다. 예를 들어 @query 유도된 구성요소에 원시 쿼리 문자열을 사용하면서 @query-param 유도된 구성요소에는 결합된 쿼리 및 폼 매개변수를 사용하는 것은 오류입니다. 메시지 구성요소 문맥에 대한 추가 고려사항은 섹션 7.4.3를 참조하세요.

구성요소 식별자는 구성요소 이름과 해당 이름과 연관된 매개변수로 구성됩니다. 각 구성요소 이름은 HTTP 필드 이름(섹션 2.1)이거나 등록된 유도된 구성요소 이름(섹션 2.2)입니다. 구성요소 식별자에 대한 가능한 매개변수는 구성요소 식별자에 따라 달라집니다. 가능한 모든 매개변수를 목록화하는 "HTTP Signature Component Parameters" 레지스트리는 섹션 6.5에 정의되어 있습니다.

단일 covered components 목록 내에서 각 구성요소 식별자는 한 번만 나타나야 MUST 합니다. 구성요소 이름이 다르거나 동일한 구성요소 이름에 대해 매개변수가 다르면 하나의 구성요소 식별자는 다른 것과 구별됩니다. 예를 들어 "foo";bar"foo";baz 같이 서로 다른 매개변수를 가진 동일한 이름의 다중 구성요소 식별자를 포함할 수 MAY 있습니다. 구성요소 식별자를 처리할 때(예: 검증 시 파싱할 때) 매개변수의 순서는 보존되어야 MUST 하지만, 두 구성요소 식별자의 동등성 비교에서는 매개변수의 순서는 중요하지 않습니다. 즉, "foo";bar;baz"foo";baz;bar는 동등하므로 동일 메시지에 둘 다 있을 수 없지만, 한 형태를 처리하는 시스템이 그것을 다른 형태로 변환하는 것은 허용되지 않습니다.

구성요소 식별자와 연관된 구성요소 값은 식별자 자체에 의해 정의됩니다. 구성요소 값은 줄 바꿈(\n) 문자를 포함해서는 MUST NOT 합니다. 일부 HTTP 메시지 구성요소는 의미를 변경하지 않으면서 비트 단위 값을 변경하는 변환을 겪을 수 있습니다(예: 필드 값의 결합). 따라서 메시지 구성요소 값은 서명 전에 정규화되어야 하며, 중계자 변환이 있더라도 서명을 검증할 수 있도록 해야 합니다. 이 문서는 식별자와 연관된 구성요소 값을 이러한 정규형으로 변환하는 규칙을 각 구성요소 식별자에 대해 정의합니다.

다음 섹션들은 구성요소 식별자 이름, 그 매개변수, 연관된 값 및 값의 정규화 규칙을 정의합니다. 메시지 구성요소를 서명 베이스로 결합하는 방법은 섹션 2.5에 정의되어 있습니다.

2.1. HTTP 필드

HTTP 필드의 구성요소 이름은 RFC 9110 섹션 5.1에 정의된 필드 이름의 소문자 형태입니다. HTTP 필드 이름은 대소문자를 구분하지 않지만, 구현체는 구성요소 이름으로 사용할 때 소문자 필드 이름(예: content-type, date, etag)을 사용해야 MUST 합니다.

HTTP 필드의 구성요소 값은 대상 메시지의 명명된 헤더 필드에서 가져온 필드 값입니다(자세한 내용은 RFC 9110 섹션 5.5 참조). 필드 값은 추가 매개변수 및 규칙(예: 아래의 reqtr 플래그)에 의해 재정의되지 않는 한 대상 메시지의 명명된 헤더 필드에서 가져와야 MUST 합니다. 대부분의 필드에서 필드 값은 [HTTP]에서 권장하는 대로 ASCII 문자열이며, 구성요소 값은 정확히 그 문자열입니다. 일부 구현에서는 다른 인코딩이 존재할 수 있으며, 모든 비-ASCII 필드 값은 서명 베이스에 추가되기 전에 ASCII로 인코딩되어야 MUST 합니다. 섹션 2.1.3에 설명된 bs 매개변수는 이러한 문제가 있는 필드 값을 래핑하는 방법을 제공합니다.

추가 매개변수 및 규칙으로 재정의되지 않는 한, HTTP 필드 값은 RFC 9110 섹션 5.2에서 정의된 대로 단일 값으로 결합되어 구성요소 값을 만들어야 MUST 합니다. 구체적으로, 다중으로 전송된 HTTP 필드는 각 값들을 단일 쉼표와 단일 공백(", ")로 연결하여 결합해야 MUST 합니다. 중계자는 쉼표 사이에 임의의 양의 공백을 넣어 값을 결합할 수 있으며, 검증자가 이 동작을 고려하지 않으면 서명이 실패할 수 있습니다. 강건성을 위해 서명된 메시지는 서명에 포함된 어떤 필드든 단일 인스턴스만 포함하도록 하는 것이 RECOMMENDED 됩니다. 특히 리스트 기반 필드의 값은 아래 엄격한 알고리즘을 사용해 직렬화하는 것이 권장됩니다. 이 접근법은 중계자를 통해 필드 값이 변경될 가능성을 줄입니다. 불가능한 경우 여러 인스턴스가 별도로 전송되어야 할 때에는, 서명자와 검증자는 리스트 기반 필드의 각 개별 필드 값을 모두 취하여 엄격한 알고리즘에 따라 결합하도록 처리하는 것이 RECOMMENDED 됩니다. 해당 필드가 List 또는 Dictionary 타입의 Structured Field라면, 섹션 2.1.1에 설명된 엄격한 Structured Field 직렬화를 요구함으로써 이 효과를 보다 직접적으로 달성할 수 있습니다.

Set-Cookie와 같은 일부 HTTP 필드([COOKIE]) 는 이러한 방식으로 필드 값을 결합하는 문법을 따르지 않아(여러 입력으로부터 결합된 출력이 모호해질 수 있음) 주의가 필요합니다. 구성요소 값은 메시지 서명 처리 과정에서 파싱되지 않고 서명 베이스의 일부로만 사용되지만(섹션 2.5 참조), 이러한 필드를 서명에 포함할 때는 결합된 값이 모호해질 수 있으므로 주의해야 합니다. bs 매개변수(섹션 2.1.3)는 그러한 문제 필드를 래핑하는 방법을 제공합니다. 이 문제에 대한 추가 논의는 섹션 7.5.6을 참조하세요.

구현체가 주어진 필드에 대해 올바르게 결합된 값을 직접 사용할 수 없는 경우, 다음 알고리즘은 리스트 기반 필드에 대해 정규화된 결과를 생성합니다:

  1. 메시지에서 필드의 각 인스턴스의 필드 값들을 그들이 발생하는 순서(또는 메시지에서 발생할 순서)로 정렬된 리스트로 만듭니다.
  2. 리스트의 각 항목에서 앞뒤의 공백을 제거합니다. HTTP 필드 값은 선행 및 후행 공백을 포함할 수 없으므로, 규격 준수 구현에서는 이 단계가 no-op가 됩니다.
  3. 행 내의 오래된 줄 접기(obs-fold)를 제거하고 이를 단일 공백(" ")으로 대체합니다. 이 동작은 RFC 9112 섹션 5.2에 설명된 대로입니다. 이 동작은 HTTP/1.1에 특화된 것이며 내부 줄 접기를 허용하지 않는 다른 HTTP 버전에는 적용되지 않습니다.
  4. 값들의 리스트를 각 항목 사이에 단일 쉼표(",")와 단일 공백(" ")을 두고 연결합니다.

그 결과 문자열이 해당 필드의 구성요소 값입니다.

일부 HTTP 필드는 대소문자 구분이 불가능한 값처럼 중간자에 의해 변경될 수 있는 여러 유효 직렬화가 있고 의미적으로 동등한 경우가 있습니다. 이러한 필드를 서명하고 처리하는 애플리케이션은 서명자와 검증자가 동일한 값을 유도할 수 있도록 어떻게 처리할지 고려해야 하며, 이에 대한 논의는 섹션 7.5.2를 참조하세요.

다음은 예시 HTTP 메시지 조각이 주어졌을 때 헤더 필드의 구성요소 값들에 대한 비규범적 예시입니다:

Host: www.example.com
Date: Tue, 20 Apr 2021 02:07:56 GMT
X-OWS-Header:   Leading and trailing whitespace.
X-Obs-Fold-Header: Obsolete
    line folding.
Cache-Control: max-age=60
Cache-Control:    must-revalidate
Example-Dict:  a=1,    b=2;x=1;y=2,   c=(a   b   c)

다음 예시는 이러한 예시 헤더 필드들에 대한 구성요소 값을 섹션 2.5에서 정의된 서명 베이스 형식으로 제시한 것입니다:

"host": www.example.com
"date": Tue, 20 Apr 2021 02:07:56 GMT
"x-ows-header": Leading and trailing whitespace.
"x-obs-fold-header": Obsolete line folding.
"cache-control": max-age=60, must-revalidate
"example-dict": a=1,    b=2;x=1;y=2,   c=(a   b   c)

빈 HTTP 필드도 메시지에 존재하는 경우 서명할 수 있습니다. 정규화된 값은 빈 문자열입니다. 예를 들어 다음 빈 헤더 필드(후행 빈 값 앞에 단일 공백 문자를 나타내기 위해 (SP)로 표기됨)는:

X-Empty-Header:(SP)

서명 베이스 생성 알고리즘(섹션 2.5)에 의해 콜론과 구성요소 식별자 뒤에 추가된 공백 다음에 빈 문자열 값으로 직렬화됩니다.

"x-empty-header":(SP)

어떤 HTTP 필드 구성요소 식별자는 특정 상황에서 다음 매개변수들을 가질 수 MAY 있으며, 각 항목은 별도의 섹션에서 자세히 설명됩니다:

sf
Structured Field 값의 엄격 직렬화(섹션 2.1.1)를 사용하여 구성요소 값이 직렬화되었음을 나타내는 부울 플래그입니다.
key
Dictionary Structured Field에서 단일 멤버 값을 선택하는 데 사용되는 문자열 매개변수(섹션 2.1.2).
bs
개별 필드 값들이 결합되기 전에 Byte Sequence 데이터 구조를 사용해 인코딩됨을 나타내는 부울 플래그(섹션 2.1.3).
req
서명된 응답에서 구성요소 값이 응답 메시지 자체가 아니라 이 응답을 유발한 요청으로부터 유도되었음을 나타내는 부울 플래그. 이 매개변수는 요청을 대상으로 하는 유도된 구성요소 식별자에도 적용될 수 있습니다(섹션 2.4).
tr
필드 값이 RFC 9110 섹션 6.5에 정의된 메시지의 트레일러에서 가져와야 함을 나타내는 부울 플래그입니다. 이 플래그가 없으면 필드 값은 메시지의 헤더 필드에서 가져옵니다(자세한 내용은 섹션 6.3섹션 2.1.4 참조).

여러 매개변수는 함께 지정될 수 MAY 있지만, 일부 조합은 중복되거나 호환되지 않습니다. 예를 들어 key 매개변수가 Dictionary 항목에 사용될 때 그 기능은 이미 포함되어 있으므로 sf 매개변수의 기능은 중복됩니다. 필드 값의 원시 바이트가 요구되는 bs 매개변수는 필드 값을 결합한 이후의 파싱된 데이터 구조를 요구하는 sf 또는 key 매개변수와 호환되지 않습니다.

추가 매개변수는 섹션 6.5에 설정된 "HTTP Signature Component Parameters" 레지스트리에 정의될 수 있습니다.

2.1.1. HTTP 구조화 필드의 엄격 직렬화

애플리케이션이 어떤 HTTP 필드의 값이 Structured Field 타입([STRUCTURED-FIELDS] 또는 그 확장/업데이트로 정의된)임을 알고 있고 기대되는 Structured Field 타입을 알고 있는 경우, 서명자는 구성요소 식별자에 sf 매개변수를 포함할 수 MAY 있습니다. 이 매개변수가 구성요소 식별자에 포함된 경우, 해당 HTTP 필드 값은 필드의 타입에 적용 가능한 RFC 8941 섹션 4에 명시된 형식적 직렬화 규칙(또는 해당 확장/업데이트의 적용 가능한 직렬화 섹션)을 사용하여 직렬화되어야 MUST 합니다. 이 과정은 값의 내부 선택적 공백을 단일 공백 문자로 치환하는 등 값의 다른 잠재적 변환을 수행할 수 있음을 유의하세요.

메시지에 다중 필드 값이 발생하는 경우, 이러한 값들은 직렬화 전에 단일 List 또는 Dictionary 구조로 결합되어야 MUST 합니다.

애플리케이션이 필드의 타입을 알지 못하거나 필드 타입을 직렬화하는 방법을 모르는 경우, 이 플래그의 사용은 오류를 발생시킵니다. 결과적으로 검증자의 시스템도 타입을 알고 있어야 이 플래그를 사용하여 필드를 신뢰성 있게 서명할 수 있습니다.

예를 들어, 다음 Dictionary 필드는 유효한 직렬화 예시입니다:

Example-Dict:  a=1,    b=2;x=1;y=2,   c=(a   b   c)

파라미터 없이 서명 베이스에 포함되면 그 값은 다음과 같을 것입니다:

"example-dict": a=1,    b=2;x=1;y=2,   c=(a   b   c)

그러나 sf 매개변수가 추가되면 값은 다음과 같이 재직렬화됩니다:

"example-dict";sf: a=1, b=2;x=1;y=2, c=(a b c)

결과 문자열이 구성요소 값으로 사용됩니다; 자세한 내용은 섹션 2.1를 참조하세요.

2.1.2. Dictionary Structured Field 멤버

애플리케이션이 특정 필드가 Dictionary Structured Field임을 알고 있는 경우, 해당 Dictionary 값의 개별 멤버는 key 매개변수와 Dictionary 멤버 키를 문자열 값으로 사용하여 식별합니다.

메시지에 다중 필드 값이 발생하면 이러한 값들은 직렬화 전에 단일 Dictionary 구조로 결합되어야 MUST 합니다.

Dictionary Structured Field의 개별 멤버 값은 RFC 8941 섹션 4.1.2에 설명된 직렬화 알고리즘을 member_value 및 그 매개변수에 적용하여 정규화됩니다(사전 키 자체는 포함하지 않음). 구체적으로, 값은 Item 또는 Inner List(두 가지 가능한 Dictionary 멤버 값)로 직렬화되며, 모든 매개변수와 가능한 하위 필드는 RFC 8941 섹션 4에 정의된 엄격 직렬화 규칙을 사용하여 직렬화됩니다(또는 해당 확장/업데이트의 적용 가능한 섹션).

주어진 필드에 대해 매개변수화된 각 키는 서명 베이스에 두 번 이상 나타나서는 MUST NOT 합니다. 매개변수화된 키는 소스 Dictionary에서 발생하는 순서와 상관없이 서명 베이스에서 아무 순서로나 나타날 MAY 있습니다.

Dictionary 키가 covered component로 지정되었지만 Dictionary에 존재하지 않는다면, 이는 서명 베이스 생성에서 오류를 발생시켜야 MUST 합니다.

다음은 애플리케이션이 Dictionary임을 아는 예시 헤더 필드가 주어졌을 때 Dictionary 멤버의 정규화된 값에 대한 비규범적 예시입니다:

Example-Dict:  a=1, b=2;x=1;y=2, c=(a   b    c), d

다음 예시는 서로 다른 구성요소 식별자들에 대한 정규화된 값을 섹션 2.5의 서명 베이스 형식으로 제시한 것입니다:

"example-dict";key="a": 1
"example-dict";key="d": ?1
"example-dict";key="b": 2;x=1;y=2
"example-dict";key="c": (a b c)

key="c"의 값은 엄격한 member_value 알고리즘에 따라 재직렬화되었고, key="d"의 값은 부울 값으로 직렬화되었음을 주목하세요.

2.1.3. 이진 래핑된 HTTP 필드

문제가 되는 직렬화(특히 여러 값을 단일 행으로 결합할 때의 문제)를 야기할 것으로 애플리케이션이 아는 HTTP 필드의 값에 대해서는, 서명자는 구성요소 식별자에 bs 매개변수를 포함하는 것이 SHOULD 권장됩니다. 이 매개변수는 필드 값들이 결합되기 전에 이진 구조로 래핑되어야 함을 나타냅니다.

이 매개변수가 구성요소 식별자에 포함된 경우, 구성요소 값은 다음 알고리즘을 사용하여 계산되어야 MUST 합니다:

  1. 입력은 메시지에 나타나는 순서대로 필드 값들의 정렬된 집합입니다.
  2. 처리된 필드 값을 누적할 빈 List를 만듭니다.
  3. 집합의 각 필드 값에 대해 다음을 수행합니다:

    11.
    필드 값에서 앞뒤 공백을 제거합니다(규격 준수 구현에서는 no-op).
    12.
    행 내의 오래된 줄 접기(obs-fold)를 제거하고 이를 단일 공백(" ")으로 대체합니다(RFC 9112 섹션 5.2 참조). 이 동작은 HTTP/1.1에 특화된 동작입니다.
    13.
    결과 필드 값의 바이트를 Byte Sequence로 인코딩합니다. 대부분의 필드는 ASCII 문자만을 허용하지만 일부 구현에서는 다른 옥텟이 포함될 수 있습니다.
    14.
    그 Byte Sequence를 List 누적기에 추가합니다.
  4. 중간 결과는 Byte Sequence 값들의 List입니다.
  5. RFC 8941 섹션 4.1.1에 설명된 List의 엄격 직렬화를 따르고 그 출력을 반환합니다.

예를 들어 내부에 쉼표가 있는 다음 필드는 개별 필드 값들을 안전하게 결합하는 것을 방해합니다:

Example-Header: value, with, lots
Example-Header: of, commas

예시에서는 동일한 필드가 의미상 다른 단일 값으로 전송될 수도 있습니다:

Example-Header: value, with, lots, of, commas

애플리케이션은 이 둘을 다르게 처리합니다. 그러나 매개변수 없이 서명 베이스에 포함하면 구성요소 값은 두 경우에서 동일할 수 있습니다:

"example-header": value, with, lots, of, commas

그러나 bs 매개변수가 추가되면, 두 개의 별도 인스턴스는 인코딩되어 다음과 같이 직렬화됩니다:

"example-header";bs: :dmFsdWUsIHdpdGgsIGxvdHM=:, :b2YsIGNvbW1hcw==:

단일 인스턴스 필드의 경우 bs 매개변수를 사용한 인코딩은 다음과 같습니다:

"example-header";bs: :dmFsdWUsIHdpdGgsIGxvdHMsIG9mLCBjb21tYXM=:

이 구성요소 값은 다중 인스턴스 필드와 구별되며, 잠재적 충돌을 방지합니다.

2.1.4. 트레일러 필드

서명자가 트레일러 필드를 서명에 포함하려는 경우, 서명자는 값이 헤더 필드가 아니라 트레일러 필드에서 가져와야 함을 나타내기 위해 tr 부울 매개변수를 반드시 포함해야 MUST 합니다.

예를 들어, 다음 메시지가 주어졌을 때:

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
Trailer: Expires

4
HTTP
7
Message
a
Signatures
0
Expires: Wed, 9 Nov 2022 07:28:00 GMT

서명자는 Trailer 헤더 필드와 Expires 트레일러 필드, 그리고 상태 코드 유도 구성요소를 서명 베이스에 추가하기로 결정합니다:

"@status": 200
"trailer": Expires
"expires";tr: Wed, 9 Nov 2022 07:28:00 GMT

필드가 헤더와 트레일러 모두에서 이용 가능한 경우, 두 값을 모두 서명할 수 MAY 있지만 값들은 별도로 서명되어야 MUST 합니다. 동일 이름의 헤더 필드 값과 트레일러 필드 값은 서명 목적상 결합되어서는 MUST NOT 합니다.

트레일러 필드는 중계자에 의해 헤더 필드로 병합되거나 완전히 삭제될 수 있으므로(RFC 9110 섹션 6.5.1 참조), 서명자가 검증자가 전송된 트레일러 값을 접근할 수 있을 것을 알지 못하는 한 트레일러를 서명에 포함하는 것은 NOT RECOMMENDED 됩니다.

2.2. 유도된 구성요소

HTTP 필드 외에도, 제어 데이터, 서명 문맥 또는 서명되는 HTTP 메시지의 다른 측면에서 유도될 수 있는 다양한 구성요소들이 있습니다. 이러한 유도된 구성요소는 구성요소 이름, 가능한 매개변수, 메시지 대상 및 그 구성요소 값의 유도 방법을 정의함으로써 서명 베이스에 포함될 수 있습니다.

유도된 구성요소 이름은 @ 문자로 시작해야 MUST 합니다. 이는 유도된 구성요소 이름을 @ 문자를 포함할 수 없는 HTTP 필드 이름과 구별하기 위함입니다(RFC 9110 섹션 5.1 참조). HTTP 메시지 서명 처리기는 유도된 구성요소 이름을 필드 이름과 별도로 처리해야 MUST 합니다(자세한 내용은 섹션 7.5.1 참조).

이 명세는 다음 유도된 구성요소들을 정의합니다:

@method
요청에 사용된 메서드(섹션 2.2.1).
@target-uri
요청의 전체 대상 URI(섹션 2.2.2).
@authority
요청 대상 URI의 authority(섹션 2.2.3).
@scheme
요청 대상 URI의 스킴(섹션 2.2.4).
@request-target
요청 대상(섹션 2.2.5).
@path
요청 대상 URI의 절대 경로 부분(섹션 2.2.6).
@query
요청 대상 URI의 쿼리 부분(섹션 2.2.7).
@query-param
요청 대상 URI의 파싱되고 인코딩된 개별 쿼리 매개변수(섹션 2.2.8).
@status
응답의 상태 코드(섹션 2.2.9).

추가 유도된 구성요소 이름은 "HTTP Signature Derived Component Names" 레지스트리(섹션 6.4)에 정의됩니다.

유도된 구성요소 값은 서명의 대상 메시지 문맥에서 가져옵니다. 이 문맥은 제어 데이터와 같이 메시지 자체에 대한 정보뿐 아니라 서명자 또는 검증자가 보유한 추가 상태와 문맥 정보를 포함할 수 있습니다. 특히 응답을 서명할 때, 서명자는 req 매개변수를 사용하여 원래 요청에서 유도된 구성요소를 포함할 수 있습니다(섹션 2.4).

request:
RFC 9110 섹션 3.4에 설명된 대로 HTTP 요청 메시지에서 유도된 값 및 그 결과. 서명의 대상 메시지가 응답인 경우, 요청을 대상으로 하는 유도된 구성요소는 req 매개변수를 사용하여 포함될 수 있습니다(섹션 2.4 참조).
response:
HTTP 응답 메시지에서 유도된 값 및 그 결과(RFC 9110 섹션 3.4 참조).
request, response:
요청 메시지 또는 응답 메시지 중 어느 것으로부터 유도된 값.

유도된 구성요소 정의는 적용될 수 있는 모든 대상 메시지 타입을 정의해야 MUST 합니다.

유도된 구성요소 값은 인쇄 가능한 문자와 공백으로 제한되어야 MUST 하고, 줄 바꿈 문자를 포함해서는 MUST NOT 합니다. 또한 유도된 구성요소 값은 공백 문자로 시작하거나 끝나서는 MUST NOT 합니다.

2.2.1. 메서드

@method 유도된 구성요소는 요청 메시지의 HTTP 메서드를 가리킵니다. 구성요소 값은 메서드 값을 문자열로 취하여 정규화합니다. 메서드 이름은 RFC 9110 섹션 9.1에 따라 대/소문자 구분이 있으므로 입력 메서드 값의 대소문자에 대해 변환을 수행하지 않음을 주의하세요. 관례적으로 표준화된 메서드 이름은 대문자이지만(예: POST), 입력값의 대소문자 변형은 적용되지 않습니다.

예를 들어, 다음 요청 메시지:

POST /path?param=value HTTP/1.1
Host: www.example.com

은 다음과 같은 @method 구성요소 값을 생성합니다:

POST

그리고 다음 서명 베이스 라인을 생성합니다:

"@method": POST

2.2.2. 대상 URI

@target-uri 유도된 구성요소는 요청 메시지의 대상 URI를 가리킵니다. 구성요소 값은 authority를 포함하여 사용 가능한 모든 URI 구성요소로 조립된 요청의 대상 URI입니다 (RFC 9110 섹션 7.1 참조).

예를 들어, HTTPS를 통해 전송된 다음 메시지:

POST /path?param=value HTTP/1.1
Host: www.example.com

은 다음과 같은 @target-uri 구성요소 값을 생성합니다:

https://www.example.com/path?param=value

그리고 다음 서명 베이스 라인을 생성합니다:

"@target-uri": https://www.example.com/path?param=value

2.2.3. 권한(authority)

@authority 유도된 구성요소는 HTTP 요청 대상 URI의 authority 구성요소를 가리키며(RFC 9110 섹션 7.2 참조), HTTP/1.1에서는 일반적으로 Host 헤더 필드로 전달되고 HTTP/2 및 HTTP/3에서는 :authority 의사-헤더로 전달됩니다. 값은 요청 대상의 호스트와 선택적으로 포트를 포함하는 완전한 정규화된 authority 문자열입니다. 구성요소 값은 RFC 9110 섹션 4.2.3의 규칙에 따라 정규화되어야 MUST 합니다. 즉, 호스트 이름은 소문자로 정규화되고 기본 포트는 생략됩니다.

예를 들어, 다음 요청 메시지:

POST /path?param=value HTTP/1.1
Host: www.example.com

은 다음과 같은 @authority 구성요소 값을 생성합니다:

www.example.com

그리고 다음 서명 베이스 라인을 생성합니다:

"@authority": www.example.com

@authority 유도된 구성요소는 Host 헤더 필드를 직접 서명하는 대신 사용하는 것이 SHOULD 권장됩니다. 자세한 내용은 섹션 7.2.4를 참조하세요.

2.2.4. 스킴

@scheme 유도된 구성요소는 HTTP 요청 대상 URL의 스킴을 가리킵니다. 구성요소 값은 RFC 9110 섹션 4.2에 정의된 대로 소문자 문자열로서 스킴입니다. 스킴은 대/소문자 구분이 없지만 서명 베이스에 포함할 때는 소문자로 정규화되어야 MUST 합니다.

예를 들어, 평문 HTTP로 전송된 다음 요청 메시지:

POST /path?param=value HTTP/1.1
Host: www.example.com

은 다음과 같은 @scheme 구성요소 값을 생성합니다:

http

그리고 다음 서명 베이스 라인을 생성합니다:

"@scheme": http

2.2.5. 요청 대상

@request-target 유도된 구성요소는 HTTP 요청 메시지의 전체 요청 대상을 가리키며(RFC 9110 섹션 7.1 참조), 구성요소 값은 요청 유형에 따라 다양한 형태를 취할 수 있습니다.

HTTP/1.1의 경우 구성요소 값은 요청 라인의 요청 대상 부분과 동일합니다. 그러나 이 값은 다른 버전의 HTTP에서 신뢰성 있게 구성하기가 더 어렵기 때문에, HTTP/1.1 이외의 버전이 사용될 가능성이 있을 때는 이 구성요소를 사용하는 것은 NOT RECOMMENDED 합니다.

origin form 값은 절대 경로와 쿼리 구성요소의 결합입니다.

예를 들어, 다음 요청 메시지:

POST /path?param=value HTTP/1.1
Host: www.example.com

은 다음과 같은 @request-target 구성요소 값을 생성합니다:

/path?param=value

그리고 다음 서명 베이스 라인을 생성합니다:

"@request-target": /path?param=value

프록시로 전송된 절대-form 값을 가진 다음 요청의 경우(완전한 대상 URI 포함):

GET https://www.example.com/path?param=value HTTP/1.1

은 다음과 같은 @request-target 구성요소 값을 생성합니다:

https://www.example.com/path?param=value

그리고 다음 서명 베이스 라인을 생성합니다:

"@request-target": https://www.example.com/path?param=value

authority-form 값을 가진 CONNECT 요청의 경우(대상 호스트와 포트 포함):

CONNECT www.example.com:80 HTTP/1.1
Host: www.example.com

은 다음과 같은 @request-target 구성요소 값을 생성합니다:

www.example.com:80

그리고 다음 서명 베이스 라인을 생성합니다:

"@request-target": www.example.com:80

asterisk-form 값을 가진 OPTIONS 요청의 경우(단일 별표 *):

OPTIONS * HTTP/1.1
Host: www.example.com

은 다음과 같은 @request-target 구성요소 값을 생성합니다:

*

그리고 다음 서명 베이스 라인을 생성합니다:

"@request-target": *

2.2.6. 경로

@path 유도된 구성요소는 HTTP 요청 메시지의 대상 경로를 가리킵니다. 구성요소 값은 대상 URI의 절대 경로로, 쿼리 구성요소나 끝의 물음표(?) 문자를 포함하지 않습니다. 값은 RFC 9110 섹션 4.2.3의 규칙에 따라 정규화되어야 MUST 합니다. 즉, 빈 경로 문자열은 단일 슬래시(/)로 정규화됩니다. 경로 구성요소는 퍼센트 인코딩된 옥텟을 디코드하기 전의 값으로 표현되며, URI의 단순 문자열 비교 규칙(RFC 3986 섹션 6.2.1)을 따릅니다.

예를 들어, 다음 요청 메시지:

GET /path?param=value HTTP/1.1
Host: www.example.com

은 다음과 같은 @path 구성요소 값을 생성합니다:

/path

그리고 다음 서명 베이스 라인을 생성합니다:

"@path": /path

2.2.7. 쿼리

@query 유도된 구성요소는 HTTP 요청 메시지의 쿼리 구성요소를 가리킵니다. 구성요소 값은 선행 물음표(?) 문자를 포함하는 전체 정규화된 쿼리 문자열입니다(RFC 3986 참조). 값은 RFC 3986 섹션 6.2.1의 단순 문자열 비교 규칙에 따라 읽히며, 퍼센트 인코딩된 옥텟은 디코드되지 않습니다.

예를 들어, 다음 요청 메시지:

GET /path?param=value&foo=bar&baz=bat%2Dman HTTP/1.1
Host: www.example.com

은 다음과 같은 @query 구성요소 값을 생성합니다:

?param=value&foo=bar&baz=bat%2Dman

그리고 다음 서명 베이스 라인을 생성합니다:

"@query": ?param=value&foo=bar&baz=bat%2Dman

다음 요청 메시지:

POST /path?queryString HTTP/1.1
Host: www.example.com

은 다음과 같은 @query 구성요소 값을 생성합니다:

?queryString

그리고 다음 서명 베이스 라인을 생성합니다:

"@query": ?queryString

빈 경로 구성요소를 포함하는 것과 마찬가지로, 서명자는 이 구성요소에 빈 쿼리 구성요소를 포함하여 이 구성요소가 메시지에서 사용되지 않음을 나타낼 수 있습니다. 요청 메시지에 쿼리 문자열이 없으면 구성요소 값은 단일 선행 물음표(?) 문자만 됩니다:

?

결과적으로 다음 서명 베이스 라인을 생성합니다:

"@query": ?

2.2.8. 쿼리 매개변수

요청 대상 URI의 쿼리 부분이 HTML 폼 매개변수 형식([HTMLURL]의 규정)으로 사용되는 경우, @query-param 유도된 구성요소는 이러한 개별 쿼리 매개변수를 지정할 수 있게 합니다. 쿼리 매개변수는 [HTMLURL]의 관련 섹션에 따라 파싱되어 (nameString, valueString) 튜플의 리스트를 생성해야 MUST 합니다. 각 구성요소 식별자의 필수 name 매개변수는 단일 쿼리 매개변수의 인코딩된 nameString을 문자열 값으로 포함합니다. 단일 이름의 쿼리 매개변수의 구성요소 값은 그 단일 쿼리 매개변수의 인코딩된 valueString입니다. 여러 서로 다른 이름의 쿼리 매개변수는 covered components에 포함될 수 MAY 있습니다. 단일 이름의 매개변수는 쿼리 문자열에서 발생하는 순서와 상관없이 covered components에서 임의의 순서로 나타날 수 MAY 있습니다.

name 매개변수의 값과 단일 이름 매개변수의 구성요소 값은 다음 과정을 통해 계산됩니다:

  1. 지정된 쿼리 매개변수의 nameString 또는 valueString을 파싱합니다(RFC 관련 섹션 참조); 이는 퍼센트 인코딩된 옥텟이 디코드된 이후의 값입니다.
  2. nameString 또는 valueString[HTMLURL]의 "percent-encode after encoding" 프로세스에 따라 인코딩하여 ASCII 문자열을 생성합니다.
  3. 그 ASCII 문자열을 출력합니다.

구성요소 값에는 선행 물음표(?), 등호(=) 또는 구분 앰퍼샌드(&) 문자가 포함되지 않음을 주의하세요. 빈 valueString을 가진 명명된 쿼리 매개변수는 구성요소 값으로 빈 문자열을 가집니다. 구현의 불일치 때문에 일부 쿼리 파싱 라이브러리는 이러한 빈 값을 제거할 수 있음을 유의하세요.

쿼리 매개변수로 지정된 이름이 쿼리 매개변수에 존재하지 않는 경우, 이는 서명 베이스 생성에서 오류를 발생시켜야 MUST 합니다.

예를 들어, 다음 요청에 대해:

GET /path?param=value&foo=bar&baz=batman&qux= HTTP/1.1
Host: www.example.com

다음과 같이 baz, qux, param 명명된 쿼리 매개변수를 지정하면 다음 @query-param 구성요소 값들이 생성됩니다:

baz: batman

qux: 빈 문자열

param: value

그리고(빈 구성요소 값 앞에 단일 후행 공백 문자를 나타내기 위해 (SP) 표기) 다음과 같은 서명 베이스 라인들이 생성됩니다:

"@query-param";name="baz": batman
"@query-param";name="qux":(SP)
"@query-param";name="param": value

이 유도된 구성요소에는 몇 가지 제한이 있습니다. 구체적으로, [HTMLURL]의 알고리즘은 퍼센트-인코딩된 UTF-8을 사용하는 쿼리 매개변수만 지원하며, 다른 인코딩은 지원하지 않습니다. 또한 동일한 이름의 매개변수가 여러 번 발생하는 경우가 실제로 신뢰할 수 있게 지원되지 않습니다. 요청에서 매개변수 이름이 여러 번 발생하면 해당 명명된 쿼리 매개변수는 포함해서 는 MUST NOT 합니다. 애플리케이션에서 다중 매개변수가 일반적인 경우에는 전체 쿼리 문자열을 @query 구성요소로 서명하는 것이 RECOMMENDED 됩니다.

인코딩 과정은 값에 줄바꿈이나 다른 문제가 있는 문자를 포함하거나 공백을 플러스(+)로 표현하는 대체 인코딩을 사용하는 쿼리 매개변수를 허용합니다. 다음 메시지의 쿼리 매개변수에 대해:

NOTE: '\' line wrapping per RFC 8792

GET /parameters?var=this%20is%20a%20big%0Amultiline%20value&\
  bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something HTTP/1.1
Host: www.example.com
Date: Tue, 20 Apr 2021 02:07:56 GMT

결과 값들은 다음과 같이 인코딩됩니다:

"@query-param";name="var": this%20is%20a%20big%0Amultiline%20value
"@query-param";name="bar": with%20plus%20whitespace
"@query-param";name="fa%C3%A7ade%22%3A%20": something

인코딩이 적용되지 않았다면 결과 값은 다음과 같을 것입니다:

"@query-param";name="var": this is a big
multiline value
"@query-param";name="bar": with plus whitespace
"@query-param";name="façade\": ": something

이 기본 문자열에는 구성요소 이름과 값에 대한 제약을 위반하는 문자가 포함되므로 유효하지 않습니다.

2.2.9. 상태 코드

@status 유도된 구성요소는 응답 메시지의 3자리 숫자 HTTP 상태 코드를 가리킵니다(RFC 9110 섹션 15 참조). 구성요소 값은 서술 텍스트 없이 HTTP 상태 코드의 직렬화된 3자리 정수입니다.

예를 들어, 다음 응답 메시지:

HTTP/1.1 200 OK
Date: Fri, 26 Mar 2010 00:05:00 GMT

은 다음과 같은 @status 구성요소 값을 생성합니다:

200

그리고 다음 서명 베이스 라인을 생성합니다:

"@status": 200

@status 구성요소 식별자는 요청 메시지에서는 사용해서는 MUST NOT 합니다.

2.3. 서명 매개변수

HTTP 메시지 서명에는 서명의 생성 및 검증과 관련된 메타데이터 속성이 있으며, 여기에는 covered components의 순서화된 집합과 매개변수의 순서화된 집합이 포함됩니다. 매개변수에는 서명 생성 시점의 타임스탬프, 검증 키 자료 식별자, 기타 유틸리티가 포함될 수 있습니다. 이 메타데이터는 서명 베이스에서 서명 매개변수용 특수 메시지 구성요소로 표현되며, 이 특수한 메시지 구성요소는 다른 구성요소들과 약간 다르게 취급됩니다. 구체적으로, 서명 매개변수 메시지 구성요소는 서명 베이스의 마지막 라인으로서 포함되는 것이 REQUIRED 하며(섹션 2.5), 구성요소 식별자 집합 내에서 해당 구성요소 식별자 자체를 포함해서는 MUST NOT 합니다.

서명 매개변수 구성요소 이름은 @signature-params입니다.

서명 매개변수 구성요소 값은 covered components의 순서화된 집합과 모든 연관 매개변수를 포함한 해당 서명에 대한 서명 매개변수의 직렬화입니다. 이러한 매개변수에는 다음 중 하나 이상이 포함될 수 있습니다:

created:
정수 타입의 UNIX 타임스탬프로서 생성 시간. 서브초 정밀도는 지원되지 않습니다. 이 매개변수의 포함은 RECOMMENDED 됩니다.
expires:
정수 타입의 UNIX 타임스탬프로서 만료 시간. 서브초 정밀도는 지원되지 않습니다.
nonce:
이 서명을 위해 생성된 무작위 고유 값의 문자열 값.
alg:
"HTTP Signature Algorithms" 레지스트리의 HTTP 메시지 서명 알고리즘을 문자열 값으로 지정.
keyid:
키 자료 식별자를 문자열 값으로 지정.
tag:
애플리케이션-특정 태그로서 문자열 값. 이 값은 특정 애플리케이션 또는 프로토콜과 관련된 서명을 식별하는 데 사용됩니다.

추가 매개변수는 "HTTP Signature Metadata Parameters" 레지스트리(섹션 6.3)에 정의될 수 있습니다. 매개변수들은 일반적인 순서가 정해져 있지 않지만, 주어진 매개변수 집합에 대해 순서를 선택하면 그 순서를 변경하지 않는 한 서명 매개변수 값이 변경되지 않습니다.

서명 매개변수 구성요소 값은 다음과 같이 RFC 8941의 규칙을 사용하여 매개변수화된 Inner List로 직렬화됩니다:

  1. 출력을 빈 문자열로 둡니다.
  2. 서명에 포함될 구성요소 식별자들의 순서를 정합니다(자기 자신인 @signature-params 는 제외). 이 순서는 한 번 정해지면 변경할 수 없습니다. 이 순서는 서명 베이스를 생성할 때 사용된 순서(섹션 2.5)와 동일해야 MUST 합니다.
  3. covered components의 구성요소 식별자들을 각자의 매개변수를 포함하여 RFC 8941의 Inner List of String 값 규칙에 따라 직렬화한 후 출력에 추가합니다. 구성요소 식별자들은 자체 매개변수를 가질 수 있으며, 이 매개변수들은 순서화된 집합입니다. 구성요소의 매개변수에 대해 순서를 선택하면 해당 순서는 변경할 수 없습니다.
  4. 서명 매개변수들에 대한 순서를 정합니다. 이 순서 또한 선택되면 변경할 수 없습니다.
  5. 사용 가능한 매개변수들을 RFC 8941의 규칙에 따라 Inner List에 순서대로 추가합니다(이 메시지 서명에 사용되지 않거나 이용할 수 없는 매개변수는 건너뜁니다).
  6. 출력은 서명 매개변수 구성요소 값을 포함합니다.

참고로, covered component 값에는 List 직렬화 대신 Inner List 직렬화가 사용되며(이는 섹션 4.1에서 Signature-Input 필드에 이 값을 포함하는 것과의 병렬성을 용이하게 하기 위함입니다), 이는 RFC 8941의 관련 섹션에 설명된 대로입니다.

다음 예시는 예시 메시지 서명의 매개변수에 대한 직렬화된 구성요소 값을 보여줍니다:

NOTE: '\' line wrapping per RFC 8792

("@target-uri" "@authority" "date" "cache-control")\
  ;keyid="test-key-rsa-pss";alg="rsa-pss-sha512";\
  created=1618884475;expires=1618884775

하나의 HTTP 메시지가 여러 서명을 포함할 수 있지만(섹션 4.3 참조), 특정 서명에 대해 사용된 서명 매개변수만 해당 서명 매개변수 항목에 포함됩니다.

2.4. 응답 메시지에서 요청 구성요소 서명

요청 메시지가 서명된 응답 메시지를 초래할 때, 서명자는 구성요소 식별자에 req 매개변수를 추가하여 요청 메시지의 부분을 서명 베이스에 포함할 수 있습니다.

req
구성요소 값이 응답 메시지 자체가 아니라 이 응답을 유발한 요청에서 유도되었음을 나타내는 부울 플래그입니다.

이 매개변수는 요청을 대상으로 하는 유도된 구성요소와 HTTP 필드 모두에 적용될 수 있으며, 동일한 의미를 갖습니다. 이 매개변수를 사용하는 메시지 구성요소의 구성요소 값은 일반적으로 계산되는 방식과 동일하지만 데이터는 서명이 적용되는 대상 응답 메시지 대신 요청 메시지에서 가져옵니다.

동일한 구성요소 이름은 req 매개변수와 함께 또는 없이 단일 서명 베이스에 포함될 수 MAY 하며, 이는 요청 메시지와 응답 메시지의 동일한 이름 구성요소를 각각 나타냅니다.

req 매개변수는 Dictionary 필드에 대한 key 매개변수와 같이 구성요소 식별자에 적절하게 다른 매개변수들과 결합될 수 MAY 합니다.

예를 들어, 다음 요청에 대한 응답을 제공할 때:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Content-Type: application/json
Content-Length: 18

{"hello": "world"}

이로 인해 다음과 같은 서명되지 않은 응답 메시지가 생성됩니다:

NOTE: '\' line wrapping per RFC 8792

HTTP/1.1 503 Service Unavailable
Date: Tue, 20 Apr 2021 02:07:56 GMT
Content-Type: application/json
Content-Length: 62
Content-Digest: sha-512=:0Y6iCBzGg5rZtoXS95Ijz03mslf6KAMCloESHObfwn\
  HJDbkkWWQz6PhhU9kxsTbARtY2PTBOzq24uJFpHsMuAg==:

{"busy": true, "message": "Your call is very important to us"}

서버는 자체 키로 응답에 서명하면서 이 응용에 대해 합리적인 양의 응답을 포함하는 여러 헤더 필드를 covered components에 포함합니다. 또한 서버는 이 응답을 유발한 원래 요청 메시지에서 유도된 몇몇 구성요소도 포함합니다. 이 예에서는 서버가 요청의 메서드, authority, 경로 및 Content-Digest를 응답 서명의 covered components에 포함합니다. 요청과 응답 모두의 Content-Digest가 응답 서명에 포함됩니다. 이 응용에서는 쿼리가 응답에 관련이 없는 것으로 간주되어 포함되지 않았습니다. 다른 애플리케이션은 섹션 1.4에 논의된 바와 같이 애플리케이션 필요에 따라 다른 결정을 내릴 것입니다.

이 예에 대한 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@status": 503
"content-digest": sha-512=:0Y6iCBzGg5rZtoXS95Ijz03mslf6KAMCloESHObf\
  wnHJDbkkWWQz6PhhU9kxsTbARtY2PTBOzq24uJFpHsMuAg==:
"content-type": application/json
"@authority";req: example.com
"@method";req: POST
"@path";req: /foo
"content-digest";req: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A\
  2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
"@signature-params": ("@status" "content-digest" "content-type" \
  "@authority";req "@method";req "@path";req "content-digest";req)\
  ;created=1618884479;keyid="test-key-ecc-p256"

서명된 응답 메시지는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

HTTP/1.1 503 Service Unavailable
Date: Tue, 20 Apr 2021 02:07:56 GMT
Content-Type: application/json
Content-Length: 62
Content-Digest: sha-512=:0Y6iCBzGg5rZtoXS95Ijz03mslf6KAMCloESHObfwn\
  HJDbkkWWQz6PhhU9kxsTbARtY2PTBOzq24uJFpHsMuAg==:
Signature-Input: reqres=("@status" "content-digest" "content-type" \
  "@authority";req "@method";req "@path";req "content-digest";req)\
  ;created=1618884479;keyid="test-key-ecc-p256"
Signature: reqres=:dMT/A/76ehrdBTD/2Xx8QuKV6FoyzEP/I9hdzKN8LQJLNgzU\
  4W767HK05rx1i8meNQQgQPgQp8wq2ive3tV5Ag==:

{"busy": true, "message": "Your call is very important to us"}

여기서 사용된 ECDSA 서명 알고리즘은 비결정적(non-deterministic)이므로, 알고리즘을 실행할 때마다 다른 서명 값이 생성된다는 점을 주의하세요. 제공된 서명 값은 주어진 키로 검증될 수 있으나, 새로 생성된 서명 값이 예시와 일치할 것으로 기대되지는 않습니다(자세한 내용은 섹션 7.3.5 참조).

요청의 구성요소 값이 응답에 반복되어 포함되지 않으므로, 요청자는 응답에서 이 구성요소 식별자 매개변수를 사용하는 서명을 검증할 수 있을 만큼 원래 메시지 구성요소 값을 충분히 오래 보관해야 MUST 합니다. 대부분의 경우 이는 요청자가 원래 요청 메시지를 보관해야 함을 의미합니다. 서명자가 응용의 필요에 따라 요청의 어떤 부분이든 응답에 포함하도록 선택할 수 있기 때문입니다. 중계자가 서버에서 처리되기 전에 요청 메시지를 변경할 수 있으므로, 애플리케이션은 클라이언트가 결과적으로 검증할 수 없게 될 변경된 값을 서명하지 않도록 주의해야 합니다.

서버가 서명된 요청에 응답하여 서명된 응답을 생성하는 것도 가능합니다. 다음은 서명된 요청의 예입니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Content-Type: application/json
Content-Length: 18
Signature-Input: sig1=("@method" "@authority" "@path" "@query" \
  "content-digest" "content-type" "content-length")\
  ;created=1618884475;keyid="test-key-rsa-pss"
Signature: sig1=:e8UJ5wMiRaonlth5ERtE8GIiEH7Akcr493nQ07VPNo6y3qvjdK\
  t0fo8VHO8xXDjmtYoatGYBGJVlMfIp06eVMEyNW2I4vN7XDAz7m5v1108vGzaDljr\
  d0H8+SJ28g7bzn6h2xeL/8q+qUwahWA/JmC8aOC9iVnwbOKCc0WSrLgWQwTY6VLp4\
  2Qt7jjhYT5W7/wCvfK9A1VmHH1lJXsV873Z6hpxesd50PSmO+xaNeYvDLvVdZlhtw\
  5PCtUYzKjHqwmaQ6DEuM8udRjYsoNqp2xZKcuCO1nKc0V3RjpqMZLuuyVbHDAbCzr\
  0pg2d2VM/OC33JAU7meEjjaNz+d7LWPg==:

{"hello": "world"}

서버는 응답의 일부와 요청의 여러 부분을 포함하도록 선택할 수 있으며, 그 결과 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@status": 503
"content-digest": sha-512=:0Y6iCBzGg5rZtoXS95Ijz03mslf6KAMCloESHObf\
  wnHJDbkkWWQz6PhhU9kxsTbARtY2PTBOzq24uJFpHsMuAg==:
"content-type": application/json
"@authority";req: example.com
"@method";req: POST
"@path";req: /foo
"@query";req: ?param=Value&Pet=dog
"content-digest";req: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A\
  2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
"content-type";req: application/json
"content-length";req: 18
"@signature-params": ("@status" "content-digest" "content-type" \
  "@authority";req "@method";req "@path";req "@query";req \
  "content-digest";req "content-type";req "content-length";req)\
  ;created=1618884479;keyid="test-key-ecc-p256"

그리고 다음과 같은 서명된 응답이 생성됩니다:

NOTE: '\' line wrapping per RFC 8792

HTTP/1.1 503 Service Unavailable
Date: Tue, 20 Apr 2021 02:07:56 GMT
Content-Type: application/json
Content-Length: 62
Content-Digest: sha-512=:0Y6iCBzGg5rZtoXS95Ijz03mslf6KAMCloESHObfwn\
  HJDbkkWWQz6PhhU9kxsTbARtY2PTBOzq24uJFpHsMuAg==:
Signature-Input: reqres=("@status" "content-digest" "content-type" \
  "@authority";req "@method";req "@path";req "@query";req \
  "content-digest";req "content-type";req "content-length";req)\
  ;created=1618884479;keyid="test-key-ecc-p256"
Signature: reqres=:C73J41GVKc+TYXbSobvZf0CmNcptRiWN+NY1Or0A36ISg6ym\
  dRN6ZgR2QfrtopFNzqAyv+CeWrMsNbcV2Ojsgg==:

{"busy": true, "message": "Your call is very important to us"}

여기서도 사용된 ECDSA 서명 알고리즘은 비결정적이므로, 알고리즘을 실행할 때마다 다른 서명 값이 생성됩니다. 제공된 서명 값은 주어진 키로 검증될 수 있으나 새로 생성된 서명 값이 예시와 일치할 것으로 기대되지는 않습니다(섹션 7.3.5 참조).

서명된 요청에 응답하여 응답에 서명하는 애플리케이션은 충돌 공격 클래스에 대한 충분한 커버리지와 보호를 제공하기 위해 요청 서명 값의 모든 구성요소를 서명하는 것이 SHOULD 권장됩니다(자세한 내용은 섹션 7.3.7 참조). 이 예의 서버는 클라이언트의 요청에 대한 Signature-Input 필드에 나열된 모든 구성요소를 응답 서명에 포함시켰습니다.

요청 메시지의 Signature 및 Signature-Input 필드를 응답의 서명 구성요소로 포함하는 것이 문법적으로는 가능하지만, 이는 NOT RECOMMENDED 됩니다. 이는 서명들의 서명이 기대하는 것처럼 포함된 구성요소에 대한 전이적((transitive)) 커버리지를 제공하지 않으며 여러 공격에 취약하기 때문입니다(자세한 내용은 섹션 7.3.7 참조). 서명 처리가 성공적으로 이루어졌음을 신호할 필요가 있는 애플리케이션은 그러한 신호를 안전하게 전송하기 위한 대체 메커니즘을 신중히 규정해야 합니다.

이 플래그를 사용할 때 응답 서명이 요청 메시지에 포함된 내용만을 커버할 수 있으므로, 응용이 요청의 메시지 콘텐츠를 응답 서명에 포함할 필요가 있다면 클라이언트는 Content-Digest 필드와 같이 해당 콘텐츠를 커버할 수 있는 수단을 포함해야 합니다. 자세한 내용은 섹션 7.2.8를 참조하세요.

req 매개변수는 요청 메시지를 대상으로 하는 서명에서 어떤 구성요소에도 사용되어서는 MUST NOT 합니다.

2.5. 서명 베이스 생성

서명 베이스는 서명으로 포함된 정규화된 HTTP 메시지 구성요소를 포함하는 ASCII 문자열[ASCII]입니다. 서명 베이스 생성 알고리즘의 입력은 순서화된 covered component 식별자 집합과 그에 연관된 값들, 그리고 섹션 2.3에서 설명된 추가 서명 매개변수들입니다.

구성요소 식별자는 [STRUCTURED-FIELDS]의 엄격한 직렬화 규칙(섹션 4)을 사용하여 직렬화됩니다. 구성요소 식별자는 구성요소 이름을 가지며, 이는 sf-string ABNF 규칙을 사용해 직렬화된 String Item 값입니다. 구성요소 식별자는 또한 parameters ABNF 규칙을 사용해 직렬화되는 정의된 매개변수를 포함할 MAY 있습니다. 섹션 2.3에 정의된 서명 매개변수 라인도 동일한 패턴을 따르지만, 그 구성요소 식별자는 고정 값의 String Item이고 매개변수가 없으며, 구성요소 값은 항상 선택적 매개변수를 가진 Inner List입니다.

이는 구성요소 이름 자체의 직렬화가 큰따옴표로 둘러싸여 있고, 매개변수는 세미콜론으로 구분된 목록으로 따름을 의미합니다. 예: "cache-control", "@authority", "@signature-params", 또는 "example-dictionary";key="foo".

출력은 다음 ABNF를 만족하는 서명 베이스를 구성하는 바이트의 순서화된 집합입니다:

signature-base = *( signature-base-line LF ) signature-params-line
signature-base-line = component-identifier ":" SP
    ( derived-component-value / *field-content )
    ; no obs-fold nor obs-text
component-identifier = component-name parameters
component-name = sf-string
derived-component-value = *( VCHAR / SP )
signature-params-line = DQUOTE "@signature-params" DQUOTE
     ":" SP inner-list

서명 베이스를 생성하려면, 서명자 또는 검증자는 서명의 covered components에 있는 각 구성요소 식별자(및 그 매개변수)에 대한 항목을 다음 알고리즘을 사용해 연결합니다. 아래에 설명된 모든 오류는 즉시 알고리즘을 실패하게 하며 서명 베이스를 출력해서는 안 됩니다.

  1. 출력을 빈 문자열로 둡니다.
  2. covered components 집합의 각 메시지 구성요소 항목(순서대로)에 대해:

    11.
    구성요소 식별자(매개변수 포함)가 이미 서명 베이스에 추가된 경우, 오류를 발생시킵니다.
    12.
    component-identifier ABNF 규칙에 따라 직렬화된 해당 covered component의 구성요소 식별자를 추가합니다. 이 직렬화는 구성요소 이름을 큰따옴표로 감싸고 매개변수를 따옴표 밖에 붙입니다.
    13.
    단일 콜론(:)을 추가합니다.
    14.
    단일 공백(" ")을 추가합니다.
    15.

    구성요소 식별자에 대한 구성요소 값을 결정합니다.

    • 구성요소 식별자에 이해하지 못하는 매개변수가 있으면 오류를 발생시킵니다.
    • bssf처럼 상호 호환되지 않는 매개변수가 함께 있으면 오류를 발생시킵니다.
    • 구성요소 식별자에 req 매개변수가 있고 대상 메시지가 요청이면 오류를 발생시킵니다.
    • 구성요소 식별자에 req 매개변수가 있고 대상 메시지가 응답이면, 구성요소 값의 문맥은 대상 응답 메시지의 관련 요청 메시지입니다. 그렇지 않으면 구성요소 값의 문맥은 대상 메시지입니다.
    • 구성요소 이름이 @ 문자로 시작하면, 유도된 구성요소에 대해 정의된 특정 규칙에 따라 메시지에서 값을 유도합니다(섹션 2.2 참조). 알려진 유효 매개변수 처리를 포함합니다. 유도된 구성요소 이름을 알 수 없거나 값을 유도할 수 없으면 오류를 발생시킵니다.
    • 구성요소 이름이 @ 문자로 시작하지 않으면, 해당 HTTP 필드 값을 섹션 2.1에 설명된 대로 정규화하고 알려진 유효 매개변수 처리를 포함합니다. 필드를 메시지에서 찾을 수 없거나 문맥에서 값을 얻을 수 없으면 오류를 발생시킵니다.
    16.
    covered component의 정규화된 구성요소 값을 추가합니다.
    17.
    단일 개행(\n)을 추가합니다.
  3. 다음과 같이 서명 매개변수 구성요소signature-params-line 규칙에 따라 추가합니다:

    11.
    정확한 값 "@signature-params"(큰따옴표 포함)인 서명 매개변수에 대한 구성요소 식별자를 component-identifier 규칙에 따라 직렬화하여 추가합니다.
    12.
    단일 콜론(:)을 추가합니다.
    13.
    단일 공백(" ")을 추가합니다.
    14.
    섹션 2.3에 정의된 대로 서명 매개변수의 정규화된 구성요소 값을 추가합니다(즉, 매개변수를 가진 Inner List Structured Field 값).
  4. 출력 문자열에 비ASCII 문자가 포함되어 있으면 오류를 발생시킵니다([ASCII]).
  5. 출력 문자열을 반환합니다.

covered components가 메시지에서 구성요소 값으로 해결될 수 없는 구성요소 식별자를 참조하는 경우, 구현체는 오류를 발생시키고 서명 베이스를 생성해서는 MUST 합니다. 이러한 상황에는 다음이 포함되지만 이에 국한되지 않습니다:

  • 서명자나 검증자가 유도된 구성요소 이름을 이해하지 못하는 경우.
  • 구성요소 이름이 메시지에 존재하지 않거나 값이 잘못된 필드를 식별하는 경우.
  • 구성요소 식별자가 알 수 없거나 해당 구성요소 식별자에 적용되지 않는 매개변수를 포함하는 경우.
  • sf 매개변수를 통해 Structured Field 직렬화가 사용된다고 표시되었지만 해당 필드가 Structured Field가 아니거나 Structured Field 타입을 구현체가 모르는 경우.
  • 구성요소 식별자가 Dictionary 멤버 식별자인데, 메시지에 해당 필드가 없거나 Dictionary Structured Field가 아니거나 값이 잘못된 경우.
  • 구성요소 식별자가 Dictionary 멤버 식별자 또는 명명된 쿼리 매개변수 식별자인데, 해당 멤버가 구성요소 값에 존재하지 않거나 값이 잘못된 경우(예: 식별자가 "example-dict";key="c"인데 Example-Dict 헤더 필드의 값이 a=1, b=2c 값이 없는 경우).

다음의 비규범적 예에서 서명되는 HTTP 메시지(요청)는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Content-Length: 18

{"hello": "world"}

covered components는 @method, @authority, @path 유도된 구성요소들에 이어서 Content-Digest, Content-Length, 및 Content-Type HTTP 헤더 필드들로 구성됩니다. 서명 매개변수는 생성 타임스탬프 1618884473와 키 식별자 test-key-rsa-pss로 이루어집니다. 여기서 명시적인 alg 매개변수가 제공되지 않은 이유는, 애플리케이션이 식별된 키에 기반해 검증자가 RSA-PSS 알고리즘을 사용함을 알고 있기 때문입니다. 이 매개변수들로 이 메시지의 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@method": POST
"@authority": example.com
"@path": /foo
"content-digest": sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX\
  +TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
"content-length": 18
"content-type": application/json
"@signature-params": ("@method" "@authority" "@path" \
  "content-digest" "content-length" "content-type")\
  ;created=1618884473;keyid="test-key-rsa-pss"

Figure 1: 비규범적 예시 서명 베이스

위 예시 서명 베이스는 표시된 예시를 끝내는 최종 개행을 포함하지 않으며, 이 명세의 다른 예시 서명 베이스들도 마찬가지입니다.


3. HTTP 메시지 서명

HTTP 메시지 서명은 HTTP 메시지의 구성요소 일부와 서명 자체에 대한 메타데이터에서 생성된 문자열에 대한 서명입니다. HTTP 메시지와 성공적으로 대조되었을 때, 해당 서명은 서명된 구성요소 집합에 관해 메시지가 서명 생성 시의 의미론적 동등함을 제공하는 암호화적 증거를 제공합니다.

3.1. 서명 생성

HTTP 메시지 서명의 생성은 서명 문맥(대상 메시지를 포함)과 애플리케이션 요구사항을 입력으로 받아 서명 값과 서명 매개변수 집합을 출력으로 내보내며, 이는 메시지에 추가되어 검증자에게 전달될 수 있습니다.

서명을 생성하려면, 서명자는 다음 알고리즘을 적용해야 MUST 합니다:

  1. 서명자는 애플리케이션이 정한 잠재적 서명 알고리즘 집합에서 HTTP 서명 알고리즘과 서명에 사용할 키 자료를 선택합니다. 서명자는 알고리즘의 요구사항(예: 키 크기나 형식)에 적합한 키 자료를 선택해야 MUST 합니다. 알고리즘과 키 자료 선택 메커니즘은 이 문서의 범위를 벗어납니다.
  2. 서명자는 서명의 생성 시간을 현재 시각으로 설정합니다.
  3. 해당하면, 서명자는 서명이 만료될 시각으로 서명의 만료 시간 속성을 설정합니다. 만료 시간은 검증자에 대한 힌트이며, 서명자가 더 이상 서명을 보증하지 않는 시점을 표현합니다. 적절한 만료 길이와 이 매개변수의 처리 요구사항은 애플리케이션별입니다.
  4. 서명자는 서명이 포함할 메시지 구성요소를 나타내는 구성요소 식별자들의 순서화된 집합을 생성하고 이 집합에 서명 메타데이터 매개변수를 첨부합니다. 이 집합의 직렬화 값은 이후 섹션 4.1에 설명된 Signature-Input 필드의 값으로 사용됩니다.

    • covered components의 순서를 한 번 선택하면, 그 순서는 서명의 수명 동안 변경해서는 MUST NOT 합니다.
    • 각 covered component 식별자는 서명 문맥에서 (1) HTTP 필드(섹션 2.1)이거나 (2) 섹션 2.2 또는 "HTTP Signature Derived Component Names" 레지스트리에 등재된 유도된 구성요소여야 MUST 합니다.
    • 요청 서명의 서명자들은 @method, @authority, @target-uri 등과 같은 메시지 제어 데이터를 covered components에 일부 또는 전부 포함하는 것이 SHOULD 권장됩니다.
    • 서명자들은 서명이 생성된 시점을 나타내기 위해 created 서명 메타데이터 매개변수를 포함하는 것이 SHOULD 권장됩니다.
    • @signature-params 유도된 구성요소 식별자는 covered component 식별자 목록에 존재해서는 MUST NOT 합니다. 이 유도된 구성요소는 항상 서명 베이스의 마지막 라인이 되어야 하며, 이를 통해 서명이 항상 자신의 메타데이터를 포함하고 메타데이터를 대체할 수 없도록 보장합니다.
    • 이 집합에 무엇을 포함할지 및 어떤 순서로 할지에 대한 추가 지침은 이 문서의 범위를 벗어납니다.
  5. 서명자는 이러한 매개변수들과 함께 서명 베이스 생성 알고리즘(섹션 2.5)을 사용하여 서명 베이스를 생성합니다.
  6. 서명자는 선택한 서명 알고리즘과 서명자가 선택한 키 자료를 사용하여 HTTP_SIGN 원시 함수를 이용해 서명 베이스에 서명합니다. HTTP_SIGN 원시와 몇 가지 구체적 서명 알고리즘의 적용은 섹션 3.3에 정의되어 있습니다.
  7. 서명 함수의 바이트 배열 출력은 섹션 4.2에 정의된 Signature 필드에 포함될 HTTP 메시지 서명 출력 값입니다.

예를 들어, 섹션 2.5의 예시 HTTP 메시지와 서명 매개변수를 사용하면, 예시 서명 베이스는 test-key-rsa-pss 키(부록 B.1.2 참조)와 섹션 3.3.1에 설명된 RSASSA-PSS 알고리즘으로 서명되어, Base64로 인코딩된 다음과 같은 메시지 서명 출력 값을 생성합니다:

NOTE: '\' line wrapping per RFC 8792

HIbjHC5rS0BYaa9v4QfD4193TORw7u9edguPh0AW3dMq9WImrlFrCGUDih47vAxi4L2\
YRZ3XMJc1uOKk/J0ZmZ+wcta4nKIgBkKq0rM9hs3CQyxXGxHLMCy8uqK488o+9jrptQ\
+xFPHK7a9sRL1IXNaagCNN3ZxJsYapFj+JXbmaI5rtAdSfSvzPuBCh+ARHBmWuNo1Uz\
VVdHXrl8ePL4cccqlazIJdC4QEjrF+Sn4IxBQzTZsL9y9TP5FsZYzHvDqbInkTNigBc\
E9cKOYNFCn4D/WM7F6TNuZO9EgtzepLWcjTymlHzK7aXq6Am6sfOrpIC49yXjj3ae6H\
RalVc/g==

Figure 2: 비규범적 예시 서명 값

여기서 사용된 RSA-PSS 알고리즘은 비결정적이므로 알고리즘을 실행할 때마다 다른 서명 값이 생성됩니다. 제공된 서명 값은 주어진 키로 검증될 수 있지만, 새로 생성된 서명 값이 예시와 일치할 것으로 기대되지는 않습니다. 자세한 내용은 섹션 7.3.5를 참조하세요.

3.2. 서명 검증

HTTP 메시지 서명의 검증은 서명 문맥(대상 메시지, 특히 그 Signature 및 Signature-Input 필드를 포함)과 애플리케이션 요구사항을 입력으로 받아 수행되는 과정입니다. 검증의 출력은 성공적인 검증(긍정) 또는 오류입니다.

서명을 검증하려면, 검증자는 다음 알고리즘을 적용해야 MUST 합니다:

  1. 섹션 4.14.2에 설명된 대로 Signature 및 Signature-Input 필드를 파싱하고, 검증할 서명들과 그 레이블을 추출합니다.

    11.
    서명 값이 둘 이상 존재하면, 검증자의 정책 및 구성에 따라 이 메시지에 대해 처리할 서명을 결정합니다. 적용 가능한 서명이 발견되지 않으면 오류를 발생시킵니다.
    12.
    선택된 Signature 필드 값에 대응하는 Signature-Input 필드 값(동일한 레이블을 가진 값)이 없으면 오류를 발생시킵니다.
  2. 선택된 Signature-Input 필드의 값을 매개변수화된 Inner List로 파싱하여 검증할 서명의 순서화된 covered components 목록과 서명 매개변수를 얻습니다.
  3. 해당 Signature 필드의 값을 파싱하여 검증할 서명의 바이트 배열 값을 얻습니다.
  4. 서명 매개변수를 검사하여 서명이 이 문서에 기술된 요구사항과, 애플리케이션이 정의한 추가 요구사항(예: 어떤 메시지 구성요소가 서명되어야 하는지 등)을 충족하는지 확인합니다(섹션 3.2.1 참조).
  5. 이 서명에 대한 검증 키 자료를 결정합니다. 키 자료가 정적 구성이나 외부 프로토콜 협상과 같은 외부 수단으로 알려져 있으면, 검증자는 해당 기법으로 키 자료를 얻습니다. 키가 서명 매개변수에 식별되어 있으면 검증자는 그 키 식별자를 역참조하여 적절한 키 자료를 얻습니다. 검증자는 이 컨텍스트에서 키 자료의 신뢰성을 결정해야 합니다. 검증자가 알지 못하거나 신뢰하지 않거나 사전 구성된 것과 일치하지 않는 키가 식별되면 검증은 MUST 실패합니다.
  6. 검증에 적용할 알고리즘을 결정합니다:

    11.
    애플리케이션이 알고 있는 허용 가능한 알고리즘 집합으로 시작합니다. 다음 단계 중 어느 하나가 이 집합에 없는 알고리즘을 선택하면 서명 검증은 실패합니다.
    12.
    알고리즘이 정적 구성이나 외부 프로토콜 협상과 같은 외부 수단으로 알려져 있으면, 검증자는 그 알고리즘을 사용합니다.
    13.
    키 자료 자체에 알고리즘 필드가 있어 알고리즘을 결정할 수 있으면, 검증자는 그 알고리즘을 사용합니다.
    14.
    알고리즘이 서명 매개변수에 섹션 2.3의 "HTTP Signature Algorithms" 레지스트리 값을 사용하여 명시되어 있으면, 검증자는 그 알고리즘을 사용합니다.
    15.
    알고리즘이 여러 곳에서 지정된 경우(예: 정적 구성, alg 서명 매개변수, 키 자료 자체의 조합), 해결된 알고리즘들은 동일해야 MUST 합니다. 동일하지 않으면 검증자는 검증을 MUST 실패시킵니다.
  7. 수신된 HTTP 메시지와 파싱된 서명 매개변수를 사용하여 섹션 2.5에 정의된 알고리즘을 사용해 서명 베이스를 재생성합니다. @signature-params 입력의 값은 이 서명의 Signature-Input 필드 값이며 섹션 2.3에서 설명된 규칙에 따라 직렬화됩니다. 여기에는 Signature-Input 필드의 레이블은 포함되지 않습니다.
  8. 키 자료가 알고리즘에 적합하면, 재생성된 서명 베이스, 키 자료, 서명 값에 대해 적절한 HTTP_VERIFY 암호 검증 알고리즘을 적용합니다. HTTP_VERIFY 원시와 몇 가지 구체적 알고리즘은 섹션 3.3에 정의되어 있습니다.
  9. 검증 알고리즘 함수의 결과가 암호 검증의 최종 결과입니다.

위 단계들 중 어느 하나라도 실패하거나 오류를 발생시키면 서명 검증은 실패합니다.

예를 들어, 레이블 sig1을 가진 서명을 test-key-rsa-pss 키(부록 B.1.2 참조)와 RSASSA-PSS 알고리즘(섹션 3.3.1)으로 다음 메시지에 대해 검증하면:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Content-Length: 18
Signature-Input: sig1=("@method" "@authority" "@path" \
  "content-digest" "content-length" "content-type")\
  ;created=1618884473;keyid="test-key-rsa-pss"
Signature: sig1=:HIbjHC5rS0BYaa9v4QfD4193TORw7u9edguPh0AW3dMq9WImrl\
  FrCGUDih47vAxi4L2YRZ3XMJc1uOKk/J0ZmZ+wcta4nKIgBkKq0rM9hs3CQyxXGxH\
  LMCy8uqK488o+9jrptQ+xFPHK7a9sRL1IXNaagCNN3ZxJsYapFj+JXbmaI5rtAdSf\
  SvzPuBCh+ARHBmWuNo1UzVVdHXrl8ePL4cccqlazIJdC4QEjrF+Sn4IxBQzTZsL9y\
  9TP5FsZYzHvDqbInkTNigBcE9cKOYNFCn4D/WM7F6TNuZO9EgtzepLWcjTymlHzK7\
  aXq6Am6sfOrpIC49yXjj3ae6HRalVc/g==:

{"hello": "world"}

적어도 method, authority, path, content-digest, content-length, content-type 항목들이 서명되어야 하고, 서명 생성 타임스탬프가 검증 시점에 충분히 최근이어야 한다는 추가 요구사항이 주어지면, 검증은 통과합니다.

3.2.1. 애플리케이션 요구사항 적용

이 문서에 명시된 검증 요구사항은 일반적인 모든 사용 사례에 적용 가능한 기준 제약 집합으로 의도됩니다. HTTP 메시지 서명을 사용하는 애플리케이션은 그들의 사용 사례에 적합한 추가 요구사항을 이 문서의 요구사항 위에 둘 MAY 있습니다.

애플리케이션이 정의할 수 있는 추가 요구사항의 비규범적 예시는 다음과 같습니다:

  • 특정 헤더 필드(예: Authorization, Content-Digest)가 서명되어야 함을 요구.
  • created 타임스탬프 기준 최대 서명 연령을 적용.
  • expires 타임스탬프의 만료 시간을 지난 서명을 거부. 만료 시간은 서명자의 힌트이며 검증자는 언제든 만료 이전에 서명을 거부할 수 있음.
  • alg 매개변수와 같은 런타임 알고리즘 신호를 금지(예: 알고리즘이 키 정보로부터 결정되는 경우).
  • keyid 매개변수의 성공적 역참조를 보장.
  • 특정 알고리즘 사용을 금지하거나 특정 알고리즘 사용을 강제.
  • 키가 특정 크기(예: 2048비트 vs 1024비트)여야 함을 요구.
  • nonce 매개변수의 고유성 강제.
  • tag 매개변수에 애플리케이션 특정 값을 요구.

애플리케이션별 요구사항은 예상되고 권장됩니다. 애플리케이션이 추가 요구사항을 정의할 때, 해당 요구사항은 서명 검증 과정 동안 강제되어야 MUST 하며, 서명이 애플리케이션 요구사항에 부합하지 않으면 서명 검증은 실패해야 MUST 합니다.

애플리케이션은 이 문서에 정의된 요구사항을 반드시 강제해야 MUST 합니다. 사용 사례에 관계없이, 애플리케이션은 이러한 요구사항을 충족하지 않는 서명을 받아들여서는 MUST NOT 합니다.

3.3. 서명 알고리즘

HTTP 메시지 서명은 키 자료, 환경, 서명자와 검증자의 요구에 적합한 암호화적 디지털 서명 또는 MAC 방식을 사용해야 MUST 합니다. 이 명세는 사용할 수 있는 서명 알고리즘을 엄격히 제한하지 않으며, 이러한 기본 요구사항을 충족하는 모든 서명 알고리즘은 HTTP 메시지 서명 애플리케이션에서 MAY 사용될 수 있습니다.

각 서명 방법에 대해, HTTP_SIGN섹션 2.5에서 정의된 서명 베이스를 바이트 배열(M)로, 그리고 서명 키 자료(Ks)를 입력으로 받아 결과 서명 바이트 배열(S)을 출력합니다:

HTTP_SIGN (M, Ks)  ->  S

각 검증 방법에 대해, HTTP_VERIFY는 재생성된 서명 베이스(M)와 검증 키 자료(Kv), 그리고 검증할 제시된 서명 바이트 배열(S)을 입력으로 받아 검증 결과(V)를 불리언으로 출력합니다:

HTTP_VERIFY (M, Kv, S) -> V

다음 섹션들은 몇몇 일반적인 서명 알고리즘을 포함하며, 이러한 암호 원시가 위의 HTTP_SIGNHTTP_VERIFY 정의에 어떻게 대응되는지를 보여줍니다. 어떤 방법을 사용할지는 alg 서명 매개변수(섹션 2.3)에 의해 명시되거나, 키 자료를 참조하거나, 서명자와 검증자 간의 상호 합의로 전달될 수 있습니다. alg 매개변수로 선택된 서명 알고리즘은 "HTTP Signature Algorithms" 레지스트리(섹션 6.2)의 값을 사용해야 MUST 합니다.

3.3.1. SHA-512를 사용하는 RSASSA-PSS

이 알고리즘으로 서명하려면, 서명자는 서명자의 개인 키(K)와 서명 베이스(M)에 대해 [RFC8017]에 정의된 RSASSA-PSS-SIGN (K, M) 함수를 적용합니다. 마스크 생성 함수는 RFC 8017에 지정된 MGF1이며 해시 함수는 SHA-512입니다([RFC6234]). 소금 길이(sLen)는 64바이트입니다. 해시 함수(SHA-512)는 서명 베이스에 적용되어 디지스트 콘텐츠를 만들고, 여기에 디지털 서명이 적용됩니다. 결과 서명 바이트 배열(S)이 섹션 3.1에서 사용되는 HTTP 메시지 서명 출력입니다.

이 알고리즘으로 검증하려면, 검증자는 공개 키 부분(n, e)과 재생성된 서명 베이스(M)에 대해 [RFC8017]에 정의된 RSASSA-PSS-VERIFY ((n, e), M, S) 함수를 적용합니다. 마스크 생성 함수는 MGF1이고 해시 함수는 SHA-512이며 소금 길이(sLen)는 64바이트입니다. 검증자는 섹션 3.2에 설명된 대로 검증할 HTTP 메시지 서명(S)을 추출합니다. 검증 함수의 결과는 제시된 서명이 유효한지 여부를 나타냅니다.

RSASSA-PSS 알고리즘의 출력은 비결정적이므로, 서명 베이스에 대해 새 서명을 다시 계산하여 기존 서명과 비교하는 것은 올바르지 않습니다. 대신 여기에 정의된 검증 알고리즘을 사용해야 합니다. 자세한 내용은 섹션 7.3.5를 참조하세요.

이 알고리즘의 사용은 alg 서명 매개변수에 rsa-pss-sha512 값을 사용하여 런타임에 표시할 수 있습니다.

3.3.2. SHA-256을 사용하는 RSASSA-PKCS1-v1_5

이 알고리즘으로 서명하려면, 서명자는 개인 키(K)와 서명 베이스(M)에 대해 [RFC8017]에 정의된 RSASSA-PKCS1-V1_5-SIGN (K, M) 함수를 적용합니다. 해시 SHA-256([RFC6234])이 서명 베이스에 적용되어 디지스트 콘텐츠를 만들고, 여기에 디지털 서명이 적용됩니다. 결과 서명 바이트 배열(S)이 섹션 3.1에서 사용되는 HTTP 메시지 서명 출력입니다.

이 알고리즘으로 검증하려면, 검증자는 공개 키 부분(n, e)과 재생성된 서명 베이스(M)에 대해 [RFC8017]에 정의된 RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S) 함수를 적용합니다. 해시 함수 SHA-256이 서명 베이스에 적용되어 검증 함수가 적용될 디지스트 콘텐츠를 만듭니다. 검증자는 섹션 3.2에 설명된 대로 검증할 HTTP 메시지 서명(S)을 추출합니다. 검증 함수의 결과는 제시된 서명이 유효한지 여부를 나타냅니다.

이 알고리즘의 사용은 alg 서명 매개변수에 rsa-v1_5-sha256 값을 사용하여 런타임에 표시할 수 있습니다.

3.3.3. SHA-256을 사용하는 HMAC

이 알고리즘으로 서명 및 검증하려면, 서명자는 공유 서명 키(K)와 서명 베이스(text)를 사용하여 HMAC 함수를 적용합니다([RFC2104], 섹션 2.5 참조). 해시 함수 SHA-256([RFC6234])은 HMAC이 적용될 다이제스트 콘텐츠를 만들기 위해 서명 베이스에 적용되며, 이를 통해 서명 결과가 생성됩니다.

서명 시, 생성된 값은 섹션 3.1에서 사용되는 HTTP 메시지 서명 출력 값입니다.

검증 시, 검증자는 검증할 HTTP 메시지 서명(S)을 섹션 3.2에 설명된 대로 추출합니다. HMAC 함수의 출력은 HTTP 메시지 서명의 값과 바이트 단위로 비교되며, 이 비교 결과가 제시된 서명의 유효성을 결정합니다.

이 알고리즘의 사용은 서명 매개변수 alg에 대해 hmac-sha256 값을 사용하여 런타임에 표시할 수 있습니다.

3.3.4. 곡선 P-256 DSS와 SHA-256을 사용하는 ECDSA

이 알고리즘으로 서명하려면, 서명자는 개인 서명 키와 서명 베이스를 사용하여 곡선 P-256을 사용하는 ECDSA 서명 알고리즘을 적용합니다([FIPS186-5], 섹션 2.5 참조). 해시 함수 SHA-256([RFC6234])은 디지털 서명이 적용될 다이제스트 콘텐츠를 만들기 위해 서명 베이스에 적용됩니다(M). 서명 알고리즘은 두 정수 값인 rs를 반환합니다. 이들은 각각 빅엔디안 부호 없는 정수로 인코딩되며, 각각 32 옥텟이 되도록 0으로 패딩됩니다. 인코딩된 값들은 r의 인코딩 값에 이어 s의 인코딩 값을 이어붙여 하나의 64-옥텟 배열을 형성합니다. 이 (r, s)의 결합 결과는 섹션 3.1에서 사용되는 HTTP 메시지 서명 출력의 바이트 배열입니다.

이 알고리즘으로 검증하려면, 검증자는 검증 키 자료의 공개 키 부분과 재생성된 서명 베이스를 사용하여 ECDSA 서명 알고리즘을 적용합니다([FIPS186-5], 섹션 3.2 참조). 해시 함수 SHA-256([RFC6234])은 검증 함수에 적용될 다이제스트 콘텐츠를 생성하기 위해 서명 베이스에 적용됩니다(M). 검증자는 섹션 3.2에 설명된 대로 검증할 HTTP 메시지 서명(S)을 추출합니다. 이 값은 rs의 인코딩 값을 순서대로 이어붙인 64-옥텟 배열입니다. 이들은 각각 빅엔디안 부호 없는 정수로 인코딩되며, 각각 32 옥텟이 되도록 0으로 패딩됩니다. 결과 서명 값 (r, s)이 서명 검증 함수의 입력으로 사용됩니다. 검증 함수의 결과가 제시된 서명의 유효 여부를 나타냅니다.

ECDSA 서명 알고리즘의 출력은 비결정적이므로, 서명 베이스에 대해 새 서명을 다시 계산하여 기존 서명과 비교하는 것은 올바르지 않습니다. 대신 여기서 정의된 검증 알고리즘을 사용해야 합니다. 자세한 내용은 섹션 7.3.5를 참조하세요.

이 알고리즘의 사용은 서명 매개변수 alg에 대해 ecdsa-p256-sha256 값을 사용하여 런타임에 표시할 수 있습니다.

3.3.5. 곡선 P-384 DSS와 SHA-384를 사용하는 ECDSA

이 알고리즘으로 서명하려면, 서명자는 개인 서명 키와 서명 베이스를 사용하여 곡선 P-384를 사용하는 ECDSA 서명 알고리즘을 적용합니다([FIPS186-5], 섹션 2.5 참조). 해시 함수 SHA-384([RFC6234])은 디지털 서명이 적용될 다이제스트 콘텐츠를 만들기 위해 서명 베이스에 적용됩니다(M). 서명 알고리즘은 두 정수 값인 rs를 반환합니다. 이들은 각각 빅엔디안 부호 없는 정수로 인코딩되며, 각각 48 옥텟이 되도록 0으로 패딩됩니다. 인코딩된 값들은 r의 인코딩 값에 이어 s의 인코딩 값을 이어붙여 하나의 96-옥텟 배열을 형성합니다. 이 (r, s)의 결합 결과는 섹션 3.1에서 사용되는 HTTP 메시지 서명 출력의 바이트 배열입니다.

이 알고리즘으로 검증하려면, 검증자는 검증 키 자료의 공개 키 부분과 재생성된 서명 베이스를 사용하여 ECDSA 서명 알고리즘을 적용합니다([FIPS186-5], 섹션 3.2 참조). 해시 함수 SHA-384([RFC6234])은 검증 함수에 적용될 다이제스트 콘텐츠를 생성하기 위해 서명 베이스에 적용됩니다(M). 검증자는 섹션 3.2에 설명된 대로 검증할 HTTP 메시지 서명(S)을 추출합니다. 이 값은 rs의 인코딩 값을 순서대로 이어붙인 96-옥텟 배열입니다. 이들은 각각 빅엔디안 부호 없는 정수로 인코딩되며, 각각 48 옥텟이 되도록 0으로 패딩됩니다. 결과 서명 값 (r, s)이 서명 검증 함수의 입력으로 사용됩니다. 검증 함수의 결과가 제시된 서명의 유효 여부를 나타냅니다.

ECDSA 서명 알고리즘의 출력은 비결정적이므로, 서명 베이스에 대해 새 서명을 다시 계산하여 기존 서명과 비교하는 것은 올바르지 않습니다. 대신 여기서 정의된 검증 알고리즘을 사용해야 합니다. 자세한 내용은 섹션 7.3.5를 참조하세요.

이 알고리즘의 사용은 서명 매개변수 alg에 대해 ecdsa-p384-sha384 값을 사용하여 런타임에 표시할 수 있습니다.

3.3.6. 곡선 edwards25519를 사용하는 EdDSA

이 알고리즘으로 서명하려면, 서명자는 개인 서명 키와 서명 베이스를 사용하여 Ed25519 알고리즘을 적용합니다(RFC8032 섹션 5.1.6, [RFC8032], 섹션 2.5 참조). 서명 베이스는 사전 해시 없이 입력 메시지(M)로 취해집니다. 서명은 RS의 64-옥텟 결합으로서 RFC8032에 지정된 방식대로 생성되며, 이는 섹션 3.1에서 사용되는 HTTP 메시지 서명 출력의 바이트 배열로 취해집니다.

이 알고리즘으로 검증하려면, 검증자는 검증 키 자료의 공개 키 부분(A)과 재생성된 서명 베이스를 사용하여 Ed25519 알고리즘을 적용합니다(RFC8032 섹션 5.1.7 참조). 서명 베이스는 사전 해시 없이 입력 메시지(M)로 취해집니다. 검증할 서명은 RFC8032에 지정된 대로 RS의 64-옥텟 결합으로 처리됩니다. 검증 함수의 결과가 제시된 서명의 유효 여부를 나타냅니다.

이 알고리즘의 사용은 서명 매개변수 alg에 대해 ed25519 값을 사용하여 런타임에 표시할 수 있습니다.

3.3.7. JSON Web Signature (JWS) 알고리즘

서명 알고리즘이 JOSE 레지스트리([RFC7518])의 JSON Object Signing and Encryption (JOSE) 서명 알고리즘인 경우, JWS 알고리즘 정의가 서명 및 검증에 적용할 서명 및 해싱 알고리즘을 결정합니다.

서명과 검증 모두에 대해 HTTP 메시지의 서명 베이스(섹션 2.5)가 전체 "JWS Signing Input"으로 사용됩니다. JOSE 헤더([JWS], [RFC7517])는 사용되지 않으며, 서명 베이스는 알고리즘을 적용하기 전에 Base64로 먼저 인코딩되지 않습니다. JWS 서명의 출력은 JOSE에서 사용하는 Base64url 인코딩 이전의 바이트 배열로 취합니다.

JWS 알고리즘은 "none"일 수 없으며, JOSE Implementation Requirement가 "Prohibited"인 알고리즘도 사용할 수 없습니다.

"JSON Web Signature and Encryption Algorithms" 레지스트리의 JWA 값은 서명 매개변수로 포함되지 않습니다. 일반적으로 JWS 알고리즘은 JSON Web Keys(JWKs)나 JOSE 구현이 공통으로 사용하는 다른 메커니즘을 통해 표시할 수 있습니다. 실제로 JWA 값은 "HTTP Signature Algorithms" 레지스트리(섹션 6.2)에 등록되지 않으므로, JOSE 서명 알고리즘을 사용할 때는 명시적인 alg 서명 매개변수가 전혀 사용되지 않습니다.


4. 메시지에 서명 포함하기

HTTP 메시지 서명은 이 명세에서 정의한 Signature-Input 및 Signature 필드를 통해 HTTP 메시지에 포함될 수 있습니다.

Signature-Input 필드는 서명이 어떻게 생성되었는지를 설명하는 covered components와 매개변수를 식별하고, Signature 필드는 서명 값을 포함합니다. 각 필드는 MAY 여러 개의 레이블 값을 포함할 수 있습니다.

HTTP 메시지 서명은 HTTP 메시지 내에서 레이블로 식별됩니다. 이 레이블은 해당 HTTP 메시지 내에서 고유해야 하며(MUST) Signature-Input 필드와 Signature 필드에 모두 사용되어야 합니다. 레이블은 서명자가 선택하지만, 섹션 5에서 설명된 프로토콜 협상에 의해 특정 레이블이 지정될 수 있습니다.

HTTP 메시지 서명은 Signature-Input 필드와 Signature 필드 둘 다를 사용해야 하며(MUST), 각 필드는 동일한 레이블을 포함해야 합니다. 한 필드에는 있고 다른 필드에는 없는 레이블이 존재하는 것은 오류입니다.

4.1. Signature-Input HTTP 필드

Signature-Input 필드는 HTTP 메시지 내에서 생성된 하나 이상의 메시지 서명에 대한 메타데이터를 포함하는 Dictionary Structured Field입니다(RFC8941 섹션 3.2 참조). 각 멤버는 단일 메시지 서명을 설명합니다. 멤버의 키는 해당 메시지 서명을 HTTP 메시지 내에서 고유하게 식별하는 레이블입니다. 멤버의 값은 Inner List로 직렬화된 covered components의 순서화된 집합이며, 레이블로 식별된 모든 서명 메타데이터 매개변수를 포함합니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig1=("@method" "@target-uri" "@authority" \
  "content-digest" "cache-control");\
  created=1618884475;keyid="test-key-rsa-pss"

서명 검증을 용이하게 하기 위해 Signature-Input 필드 값은 서명 베이스의 @signature-params 값 생성에 사용된 동일한 직렬화 값을 반드시 포함해야 MUST 합니다(섹션 2.3 참조). 구조화된 필드 값에서는 리스트 순서와 매개변수 순서를 보존해야 합니다.

서명자는 서명이 메시지 내용을 처리한 이후에 메시지를 서명하기 위해 Signature-Input 필드를 트레일러로 포함할 수 MAY 있습니다. 그러나 중계자는 [HTTP]에 따라 트레일러를 삭제할 수 있으므로, Signature-Input 필드를 서명이 실수로 제거되는 것을 피하기 위해 가능한 경우 헤더 필드로만 포함하는 것이 RECOMMENDED 됩니다.

하나의 HTTP 메시지에 여러 개의 Signature-Input 필드를 포함할 수 MAY 있습니다. 서명 레이블은 모든 필드 값 전반에 걸쳐 고유해야 합니다(MUST).

4.2. Signature HTTP 필드

Signature 필드는 대상 메시지의 서명 문맥에서 생성된 하나 이상의 메시지 서명을 포함하는 Dictionary Structured Field입니다(RFC8941 섹션 3.2 참조). 멤버의 키는 해당 메시지 서명을 HTTP 메시지 내에서 고유하게 식별하는 레이블입니다. 멤버의 값은 레이블로 식별된 메시지 서명의 서명 값을 포함하는 Byte Sequence입니다:

NOTE: '\' line wrapping per RFC 8792

Signature: sig1=:P0wLUszWQjoi54udOtydf9IWTfNhy+r53jGFj9XZuP4uKwxyJo\
  1RSHi+oEF1FuX6O29d+lbxwwBao1BAgadijW+7O/PyezlTnqAOVPWx9GlyntiCiHz\
  C87qmSQjvu1CFyFuWSjdGa3qLYYlNm7pVaJFalQiKWnUaqfT4LyttaXyoyZW84jS8\
  gyarxAiWI97mPXU+OVM64+HVBHmnEsS+lTeIsEQo36T3NFf2CujWARPQg53r58Rmp\
  Z+J9eKR2CD6IJQvacn5A4Ix5BUAVGqlyp8JYm+S/CWJi31PNUjRRCusCVRj05NrxA\
  BNFv3r5S9IXf2fYJK+eyW4AiGVMvMcOg==:

서명자는 서명이 메시지 내용을 처리한 이후에 메시지를 서명하기 위해 Signature 필드를 트레일러로 포함할 수 MAY 있습니다. 그러나 중계자는 [HTTP]에 따라 트레일러를 삭제할 수 있으므로, Signature 필드를 서명이 실수로 제거되는 것을 피하기 위해 가능한 경우 헤더 필드로만 포함하는 것이 RECOMMENDED 됩니다.

하나의 HTTP 메시지에 여러 개의 Signature 필드를 포함할 수 MAY 있습니다. 서명 레이블은 모든 필드 값 전반에 걸쳐 고유해야 합니다(MUST).

4.3. 다중 서명

하나의 메시지에 서로 다른 여러 서명을 포함할 수 MAY 있습니다. 각 서로 다른 서명은 고유한 레이블을 가져야 MUST 합니다. 이러한 다중 서명은 동일 서명자가 모두 추가할 수도 있고 여러 다른 서명자들로부터 올 수도 있습니다. 예를 들어, 동일한 메시지 구성요소를 서로 다른 키나 알고리즘으로 서명하여 다양한 검증자 역량을 지원하거나, 리버스 프록시가 클라이언트의 원래 서명 값을 포함하여 서비스 호스트로 요청을 전달할 때 클라이언트에 대한 정보를 필드에 포함시킬 수 있습니다.

다음 비규범적 예시는 클라이언트의 서명된 요청으로 시작합니다. 리버스 프록시는 이 요청을 받아 클라이언트의 서명을 검증합니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Length: 18
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Signature-Input: sig1=("@method" "@authority" "@path" \
  "content-digest" "content-type" "content-length")\
  ;created=1618884475;keyid="test-key-ecc-p256"
Signature: sig1=:X5spyd6CFnAG5QnDyHfqoSNICd+BUP4LYMz2Q0JXlb//4Ijpzp\
  +kve2w4NIyqeAuM7jTDX+sNalzA8ESSaHD3A==:

{"hello": "world"}

프록시는 메시지를 원본 서버로 전달하기 전에 대상 호스트를 변경하고 [RFC7239]에 정의된 Forwarded 헤더 필드를 추가하는 등 메시지를 변경합니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: origin.host.internal.example
Date: Tue, 20 Apr 2021 02:07:56 GMT
Content-Type: application/json
Content-Length: 18
Forwarded: for=192.0.2.123;host=example.com;proto=https
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Signature-Input: sig1=("@method" "@authority" "@path" \
  "content-digest" "content-type" "content-length")\
  ;created=1618884475;keyid="test-key-ecc-p256"
Signature: sig1=:X5spyd6CFnAG5QnDyHfqoSNICd+BUP4LYMz2Q0JXlb//4Ijpzp\
  +kve2w4NIyqeAuM7jTDX+sNalzA8ESSaHD3A==:

{"hello": "world"}

프록시는 들어오는 클라이언트의 서명을 검증하고, 원본 서버로 전달하기 전에 새 메시지에 대해 자체 서명을 추가하여 전달하는 방식으로 원본 서버에 요청의 성격에 대해 자신의 진술을 할 수 있는 위치에 있습니다. 또한 프록시는 원본 서버의 처리에 관련된 원래 메시지의 모든 요소를 포함합니다. 많은 경우 프록시는 클라이언트 서명이 포함한 동일한 구성요소들을 모두 포함하려 할 것이며, 다음 예는 그런 경우입니다. 이 예에서 프록시는 변경한 새 authority 값을 서명에 포함하며, 자체 서명에 Forwarded 헤더 필드도 추가합니다. 프록시는 자신의 키와 알고리즘을 식별하고, 이 예에서는 서명이 짧은 시간 창 이후에는 프록시가 이 서명된 메시지를 보증하지 않음을 나타내기 위해 만료 시간을 포함합니다. 이로 인해 생성되는 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@method": POST
"@authority": origin.host.internal.example
"@path": /foo
"content-digest": sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX\
  +TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
"content-type": application/json
"content-length": 18
"forwarded": for=192.0.2.123;host=example.com;proto=https
"@signature-params": ("@method" "@authority" "@path" \
  "content-digest" "content-type" "content-length" "forwarded")\
  ;created=1618884480;keyid="test-key-rsa";alg="rsa-v1_5-sha256"\
  ;expires=1618884540

그리고 서명 출력 값은 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

S6ZzPXSdAMOPjN/6KXfXWNO/f7V6cHm7BXYUh3YD/fRad4BCaRZxP+JH+8XY1I6+8Cy\
+CM5g92iHgxtRPz+MjniOaYmdkDcnL9cCpXJleXsOckpURl49GwiyUpZ10KHgOEe11s\
x3G2gxI8S0jnxQB+Pu68U9vVcasqOWAEObtNKKZd8tSFu7LB5YAv0RAGhB8tmpv7sFn\
Im9y+7X5kXQfi8NMaZaA8i2ZHwpBdg7a6CMfwnnrtflzvZdXAsD3LH2TwevU+/PBPv0\
B6NMNk93wUs/vfJvye+YuI87HU38lZHowtznbLVdp770I6VHR6WfgS9ddzirrswsE1w\
5o0LV/g==

이 값들은 프록시에 의해 HTTP 요청 메시지에 추가됩니다. 원래 서명은 레이블 sig1 아래에 포함되고, 리버스 프록시의 서명은 레이블 proxy_sig 아래에 포함됩니다. 프록시는 test-key-rsa 키를 사용하여 rsa-v1_5-sha256 서명 알고리즘으로 서명을 생성하고, 클라이언트의 원래 서명은 키 test-key-rsa-pss와 RSA-PSS 알고리즘을 사용하여 생성되었습니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: origin.host.internal.example
Date: Tue, 20 Apr 2021 02:07:56 GMT
Content-Type: application/json
Content-Length: 18
Forwarded: for=192.0.2.123;host=example.com;proto=https
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Signature-Input: sig1=("@method" "@authority" "@path" \
    "content-digest" "content-type" "content-length")\
    ;created=1618884475;keyid="test-key-ecc-p256", \
  proxy_sig=("@method" "@authority" "@path" "content-digest" \
    "content-type" "content-length" "forwarded")\
    ;created=1618884480;keyid="test-key-rsa";alg="rsa-v1_5-sha256"\
    ;expires=1618884540
Signature: sig1=:X5spyd6CFnAG5QnDyHfqoSNICd+BUP4LYMz2Q0JXlb//4Ijpzp\
    +kve2w4NIyqeAuM7jTDX+sNalzA8ESSaHD3A==:, \
  proxy_sig=:S6ZzPXSdAMOPjN/6KXfXWNO/f7V6cHm7BXYUh3YD/fRad4BCaRZxP+\
    JH+8XY1I6+8Cy+CM5g92iHgxtRPz+MjniOaYmdkDcnL9cCpXJleXsOckpURl49G\
    wiyUpZ10KHgOEe11sx3G2gxI8S0jnxQB+Pu68U9vVcasqOWAEObtNKKZd8tSFu7\
    LB5YAv0RAGhB8tmpv7sFnIm9y+7X5kXQfi8NMaZaA8i2ZHwpBdg7a6CMfwnnrtf\
    lzvZdXAsD3LH2TwevU+/PBPv0B6NMNk93wUs/vfJvye+YuI87HU38lZHowtznbL\
    Vdp770I6VHR6WfgS9ddzirrswsE1w5o0LV/g==:

{"hello": "world"}

프록시는 또한 원래 메시지의 Signature 및 Signature-Input 필드 값을 새 서명의 covered components에 포함시킬 수 있지만, 이는 서명 값을 서명하는 데 알려진 약점 때문에 NOT RECOMMENDED 됩니다(섹션 7.3.7 참조). 프록시는 클라이언트의 서명을 검증할 수 있는 위치에 있고, 프록시가 메시지에 가하는 변경은 원본 서버가 메시지를 볼 때 기존 서명을 무효화할 것입니다. 이 예에서 원본 서버는 authority 변경을 설명할 추가 정보를 자신의 서명 문맥에 가질 수 있지만, 이는 추가 구성과 각별한 주의를 요구합니다(자세한 내용은 섹션 7.4.4 참조). 다른 애플리케이션에서는 원본 서버가 원래 서명을 직접 검증할 수 없지만, 프록시가 클라이언트 서명을 적절히 검증했음을 확인하기를 원할 수 있습니다. 서명의 성공적인 처리 또는 수신을 신호해야 하는 애플리케이션은 그러한 신호를 안전하게 전송하기 위한 대체 메커니즘을 신중히 규정해야 합니다.


5. 서명 요청

서명자는 요청이나 응답에 자유롭게 서명을 첨부할 수 있지만, 잠재적 검증자가 잠재적 서명자에게 서명을 기대한다는 신호를 보내기 위해 Accept-Signature 필드를 사용하는 것이 종종 바람직합니다.

Accept-Signature 필드가 HTTP 요청 메시지에 포함되어 전송될 때, 해당 필드는 클라이언트가 서버에게 식별된 매개변수를 사용해 응답에 서명해 주기를 원함을 나타내며, 대상 메시지는 이 요청에 대한 응답입니다. 이러한 서명 협상을 지원하는 리소스에서 오는 모든 응답은 캐시가 다른 요청을 위해 의도된 서명이 포함된 응답을 반환하지 않도록 비캐시 가능하거나 Accept-Signature를 나열하는 Vary 헤더 필드를 포함해야 SHOULD 합니다.

Accept-Signature 필드가 HTTP 응답 메시지에서 사용될 때, 해당 필드는 서버가 식별된 매개변수를 사용해 클라이언트가 다음 번 서버에 대한 요청에 서명하기를 원함을 나타내며, 대상 메시지는 클라이언트의 다음 요청입니다. 클라이언트는 동일한 방식으로 동일 서버에 대한 향후 요청에도 계속 서명하기로 선택할 수 있습니다.

Accept-Signature 필드의 대상 메시지는 Accept-Signature 필드에 표시된 모든 레이블된 서명을 포함해야 하며, 각 서명은 Accept-Signature 필드에서 식별된 동일한 구성요소를 커버해야 MUST 합니다.

Accept-Signature 필드의 발신자는 대상 메시지 유형에 적합한 식별자만 포함해야 MUST 합니다. 예를 들어 대상 메시지가 요청인 경우, 포함되는 구성요소는 @status 구성요소 식별자를 포함할 수 없습니다.

5.1. Accept-Signature 필드

Accept-Signature 필드는 Dictionary Structured Field(섹션 3.2 참조) 로, 대상 HTTP 메시지의 구성요소에서 생성될 하나 이상의 요청된 메시지 서명에 대한 메타데이터를 포함합니다. 각 멤버는 단일 메시지 서명을 설명합니다. 멤버의 키는 대상 HTTP 메시지의 문맥에서 요청된 메시지 서명을 고유하게 식별하는 레이블입니다.

멤버의 값은 섹션 2.3에 정의된 직렬화 프로세스를 사용하여 대상 메시지의 원하는 covered components(허용된 구성요소 메타데이터 매개변수를 포함)를 직렬화한 것입니다:

NOTE: '\' line wrapping per RFC 8792

Accept-Signature: sig1=("@method" "@target-uri" "@authority" \
  "content-digest" "cache-control");\
  keyid="test-key-rsa-pss";created;tag="app-123"

구성요소 식별자 목록은 요청된 서명에 포함되어야 할 정확한 구성요소 식별자 집합과 해당되는 모든 구성요소 매개변수를 나타냅니다.

서명 요청은 서명자에게 원하는 동작을 나타내는 서명 메타데이터 매개변수를 포함할 수 MAY 있습니다. 이 명세에서 정의하는 동작은 다음과 같습니다:

created:
서명자에게 생성 시간(created)을 생성해 포함하도록 요청합니다. 이 매개변수는 서명 요청으로 전송될 때 값이 없습니다.
expires:
서명자에게 만료 시간(expires)을 생성해 포함하도록 요청합니다. 이 매개변수는 서명 요청으로 전송될 때 값이 없습니다.
nonce:
서명자에게 이 매개변수의 값을 대상 서명의 nonce로 포함하도록 요청합니다.
alg:
서명자에게 "HTTP Signature Algorithms" 레지스트리에서 지정된 표시된 서명 알고리즘을 사용하여 대상 서명을 생성하도록 요청합니다.
keyid:
서명자에게 표시된 키 자료를 사용하여 대상 서명을 생성하도록 요청합니다.
tag:
서명자에게 이 매개변수의 값을 대상 서명의 tag로 포함하도록 요청합니다.

5.2. Accept-Signature 처리

Accept-Signature 필드의 수신자는 해당 헤더를 다음과 같이 이행합니다:

  1. 필드 값을 Dictionary로 파싱합니다.
  2. Dictionary의 각 멤버에 대해:

    11.
    키는 섹션 4.1에 명시된 대로 출력 서명의 레이블로 취합니다.
    12.
    멤버의 값을 파싱하여 covered component 식별자 집합을 얻습니다.
    13.
    covered components가 대상 메시지에 적용 가능한지 판단합니다. 적용되지 않으면 프로세스는 실패하고 오류를 반환합니다.
    14.
    요청된 매개변수(예: 서명 알고리즘 및 키 자료)를 처리합니다. 요청된 매개변수를 이행할 수 없거나 요청된 매개변수가 대상 메시지에 적절하다고 판단되는 것과 충돌하면 프로세스는 실패하고 오류를 반환합니다.
    15.
    서명을 완료하는 데 필요한 추가 매개변수를 선택하고 생성합니다.
    16.
    대상 메시지에 대해 HTTP 메시지 서명을 생성합니다.
    17.
    Signature-Input 및 Signature 필드 값을 생성하고 이를 레이블과 연결합니다.
  3. 선택적으로 Accept-Signature 필드에 없는 고유한 레이블로 추가적인 Signature-Input 및 Signature 필드 값을 생성합니다.
  4. 모든 레이블된 Signature-Input 및 Signature 필드 값을 결합하여 두 필드를 대상 메시지에 첨부합니다.

이 프로세스에 따라 대상 메시지에 적용된 서명은 동일한 레이블을 가져야 MUST, 동일한 covered components 집합을 포함해야 MUST, 요청된 모든 매개변수를 처리해야 하며 MAY 추가 매개변수를 가질 수 있습니다.

Accept-Signature 필드의 수신자는 애플리케이션 매개변수에 맞지 않는 서명 요청을 무시할 MAY 있습니다.

대상 메시지는 Accept-Signature 필드에 명시되지 않은 추가 서명을 포함할 수 MAY 있습니다. 예를 들어, 추가 메시지 구성요소를 커버하기 위해, 서명자는 추가 구성요소와 요청된 서명의 서명 출력을 포함하는 두 번째 서명을 생성할 수 있습니다.


6. IANA 검토 사항

IANA는 하나의 레지스트리를 업데이트하고 네 개의 새로운 레지스트리를 생성했습니다. 다음 섹션에서 설명합니다.

6.1. HTTP 필드 이름 등록

IANA는 "Hypertext Transfer Protocol (HTTP) Field Name Registry"의 항목들을 다음과 같이 업데이트했습니다:

표 1: Hypertext Transfer Protocol (HTTP) 필드 이름 레지스트리 업데이트
필드 이름 상태 참조
Signature-Input permanent 섹션 4.1 of RFC 9421
Signature permanent 섹션 4.2 of RFC 9421
Accept-Signature permanent 섹션 5.1 of RFC 9421

6.2. HTTP 서명 알고리즘 레지스트리

이 문서는 HTTP 서명 알고리즘을 정의하며, IANA는 "HTTP Signature Algorithms"라는 새 레지스트리를 생성하고 유지합니다. 이 레지스트리의 초기 값은 섹션 6.2.2에 제시되어 있습니다. 향후 할당 및 기존 할당의 수정은 Specification Required 등록 정책을 통해 이루어집니다([RFC8126]).

이 레지스트리에 나열된 알고리즘은 이 명세와 함께 애플리케이션이 사용할 수 있는 일부 암호화 알고리즘을 식별하지만, 항목은 가능한 알고리즘의 전체 목록을 나타내지 않으며 특정 애플리케이션에 대한 적합성을 나타내지 않습니다. 애플리케이션은 서명자와 검증자가 안전하고 결정론적으로 알고리즘 매개변수에 합의할 수 있는 한 필요에 맞는 어떤 알고리즘이라도 구현할 수 있습니다. 애플리케이션이 런타임에 alg 서명 매개변수를 사용해 특정 알고리즘의 사용을 신호해야 할 때, 이 레지스트리는 해당 매개변수 값과 특정 알고리즘 간의 매핑을 제공합니다. 그러나 alg 매개변수의 사용은 알고리즘 혼동 및 대체 공격을 피하기 위해 주의해서 다루어져야 합니다(자세한 내용은 섹션 7 참조).

Status 값은 표준화 상태와 IETF 또는 보안 관련 표준 개발 기구(SDO)와 같은 관련 이해관계자들의 광범위한 의견을 반영해야 합니다. 알고리즘이 처음 등록될 때 지정 전문가는(Designated Expert) 알고리즘이 일반적으로 안전하다고 권고될 합의가 있으면 Status 필드를 "Active"로, 합의가 이루어지지 않은 실험적 알고리즘이라면 "Provisional"로 설정해야 합니다. "Provisional"은 알고리즘이 알려진 취약점이 있음을 의미하지 않으며 단지 보안 속성이 충분히 검증되지 않았음을 나타냅니다. 향후 등록된 알고리즘에 결함이 발견되면 레지스트리 항목을 업데이트하고 "Deprecated" 로 표시할 수 있습니다. 이는 애플리케이션이 특정 알고리즘을 사용할 수 없게 하지는 않지만, 알려진 문제에 대한 경고를 제공하여 고려하도록 합니다. DE는 또한 상태 값에 대한 설명과 참조를 포함하도록 보장해야 하며, 이는 Deprecated 알고리즘에 특히 중요합니다.

DE는 다음을 수행해야 합니다:

  • 등록된 알고리즘 식별자가 참조하는 알고리즘이 모든 매개변수(예: salt, hash, 필요한 키 길이)를 완전히 정의하도록 보장합니다.
  • 알고리즘 정의가 HTTP_SIGNHTTP_VERIFY 원시 함수의 입력과 출력을 기저 암호 알고리즘에 어떻게 매핑하는지를 완전히 명시하도록 보장합니다.
  • 기존 등록의 별칭인 등록 요청을 거부합니다.
  • 모든 등록이 섹션 6.2.1에 제시된 템플릿을 따르도록 보장합니다. 여기에는 이름 길이가 지나치지 않으면서도 고유하고 인식 가능하도록 하는 것이 포함됩니다.

이 명세는 알고리즘 이름에 주요 매개변수를 포함시켜 알고리즘 이름이 고유하고 인식 가능하도록 합니다. 그러나 레지스트리의 알고리즘 식별자는 전체 문자열 값으로 해석되어야 하며 부분으로 분해해서 파싱해 매개변수를 결정해서는 안 됩니다. 즉, 구현자들은 rsa-pss-sha512를 특정 해시, 마스크, 소금 값이 정의된 하나의 알고리즘으로 이해해야 하며, 문자열의 부분을 파싱해 매개변수를 결정해서는 안 됩니다.

6.2.1. 등록 템플릿

Algorithm Name:
HTTP 서명 알고리즘에 대한 식별자입니다. 이름은 sf-string ABNF 규칙에 따르는 ASCII 문자열이어야 MUST 하며, 길이는 가급적 20자를 초과하지 않는 것이 SHOULD NOT 추천됩니다. 식별자는 레지스트리 내에서 고유해야 MUST 합니다.
Description:
서명 베이스를 서명하는 데 사용되는 알고리즘에 대한 간단한 설명입니다.
Status:
알고리즘의 상태입니다. MUST 다음 값 중 하나로 시작해야 하며 추가 설명을 포함할 수 있습니다: "Active", "Provisional", "Deprecated".
Reference:
알고리즘을 명시하는 문서에 대한 참조, 가능하면 해당 문서를 가져올 수 있는 URI를 포함합니다.

6.2.2. 초기 내용

다음 표는 "HTTP Signature Algorithms" 레지스트리의 초기 내용을 포함합니다.

표 2: HTTP Signature Algorithms 레지스트리의 초기 내용
Algorithm Name Description Status Reference
rsa-pss-sha512 SHA-512를 사용하는 RSASSA-PSS Active 섹션 3.3.1 of RFC 9421
rsa-v1_5-sha256 SHA-256을 사용하는 RSASSA-PKCS1-v1_5 Active 섹션 3.3.2 of RFC 9421
hmac-sha256 SHA-256을 사용하는 HMAC Active 섹션 3.3.3 of RFC 9421
ecdsa-p256-sha256 곡선 P-256 DSS와 SHA-256을 사용하는 ECDSA Active 섹션 3.3.4 of RFC 9421
ecdsa-p384-sha384 곡선 P-384 DSS와 SHA-384를 사용하는 ECDSA Active 섹션 3.3.5 of RFC 9421
ed25519 곡선 edwards25519를 사용하는 EdDSA Active 섹션 3.3.6 of RFC 9421

6.3. HTTP 서명 메타데이터 매개변수 레지스트리

이 문서는 서명 매개변수 구조(섹션 2.3)를 정의하며, 여기에는 메시지 서명에 대한 메타데이터를 포함하는 매개변수가 있을 수 있습니다. IANA는 "HTTP Signature Metadata Parameters" 라는 새 레지스트리를 생성하고 유지하여 서명 매개변수 구조의 멤버 값에서 사용하기 위해 정의된 매개변수 집합을 기록하고 유지합니다. 이 레지스트리의 초기 값은 섹션 6.3.2에 제시되어 있습니다. 향후 할당 및 수정은 Expert Review 등록 정책을 통해 이루어집니다([RFC8126]).

DE는 다음을 수행해야 합니다:

  • 이름이 섹션 6.3.1에 제시된 템플릿을 따르는지 확인합니다; 여기에는 이름의 길이가 지나치지 않으면서도 고유하고 정의된 기능에 대해 인식 가능하도록 하는 것이 포함됩니다.

  • 정의된 기능이 명확하고 다른 등록된 매개변수와 충돌하지 않는지 확인합니다.

  • 메타데이터 매개변수의 정의에 정상 서명 프로세스의 일부로 사용될 때와 Accept-Signature 필드에서 사용될 때의 동작을 포함하도록 합니다.

6.3.1. 등록 템플릿

Name:
HTTP 서명 메타데이터 매개변수의 식별자입니다. 이름은 RFC8941의 key ABNF 규칙을 따르는 ASCII 문자열이어야 MUST 하며, 길이는 가급적 20자를 초과하지 않는 것이 SHOULD NOT 추천됩니다. 식별자는 레지스트리 내에서 고유해야 MUST 합니다.
Description:
메타데이터 매개변수와 그것이 나타내는 바에 대한 간단한 설명입니다.
Reference:
매개변수를 명시하는 문서에 대한 참조, 가능하면 해당 문서를 가져올 수 있는 URI를 포함합니다.

6.3.2. 초기 내용

다음 표는 "HTTP Signature Metadata Parameters" 레지스트리의 초기 내용을 포함합니다. 표의 각 행은 레지스트리의 개별 항목을 나타냅니다.

표 3: HTTP Signature Metadata Parameters 레지스트리 초기 내용
Name Description Reference
alg 명시된 서명 알고리즘 섹션 2.3 of RFC 9421
created 서명 생성 시각 타임스탬프 섹션 2.3 of RFC 9421
expires 제안된 서명 만료 시각 타임스탬프 섹션 2.3 of RFC 9421
keyid 이 서명 생성에 사용되는 서명 및 검증 키의 키 식별자 섹션 2.3 of RFC 9421
nonce 단일 사용 nonce 값 섹션 2.3 of RFC 9421
tag 서명에 대한 애플리케이션-특정 태그 섹션 2.3 of RFC 9421

6.4. HTTP 서명 유도된 구성요소 이름 레지스트리

이 문서는 HTTP 메시지 구성요소를 정규화하는 방법을 정의하며, HTTP 필드 외부의 대상 메시지 문맥에서 유도할 수 있는 구성요소도 포함합니다. 이러한 유도된 구성요소는 고유한 문자열인 구성요소 이름으로 식별됩니다. 유도된 구성요소의 이름은 항상 "at"(@) 기호로 시작하여 HTTP 필드 이름과 구별됩니다. IANA는 "HTTP Signature Derived Component Names" 라는 새 레지스트리를 생성하고 유지하여 필드가 아닌 구성요소 이름들과 해당 구성요소 값을 생성하는 방법을 기록하고 유지합니다. 초기 값은 섹션 6.4.2에 제시되어 있습니다. 향후 할당 및 수정은 Expert Review 등록 정책을 통해 이루어집니다([RFC8126]).

DE는 다음을 기대합니다:

  • 이름이 섹션 6.4.1에 제시된 템플릿을 따르는지 확인합니다; 여기에는 이름 길이가 지나치지 않으면서도 고유하고 정의된 기능에 대해 인식 가능하도록 하는 것이 포함됩니다.
  • 등록 요청이 나타내는 구성요소 값이 대상 HTTP 메시지에서 결정론적으로 유도될 수 있는지 확인합니다.
  • 등록 요청에 대해 정의된 매개변수가 구성요소 값에 미치는 영향이 명확히 문서화되어 있는지 확인합니다.

DE는 등록이 기존 유도된 구성요소 정의와 충분히 구별되는지 확인해야 합니다.

등록된 항목의 상태를 "Deprecated"로 설정할 때 DE는 비권고 사유와 사용 중단 방법에 대한 지침을 문서화해야 합니다.

6.4.1. 등록 템플릿

Name:
HTTP 유도된 구성요소의 이름입니다. 이름은 "at"(@) 문자로 시작해야 하며 그 다음에는 소문자(a-z), 숫자(0-9), 하이픈("-")만으로 구성된 ASCII 문자열이 와야 합니다. 길이는 가급적 20자를 초과하지 않는 것이 권장됩니다. 이름은 레지스트리 내에서 고유해야 MUST 합니다.
Description:
유도된 구성요소에 대한 설명입니다.
Status:
알고리즘 상태에 대한 간단한 텍스트 설명입니다. 설명은 "Active" 또는 "Deprecated"로 시작해야 하며, 필요에 따라 추가 설명을 제공할 수 있습니다. "Deprecated" 값은 해당 구성요소 이름이 더 이상 사용을 권장하지 않음을 나타냅니다.
Target:
유도된 매개변수의 유효한 메시지 대상입니다. "Request", "Response", 또는 "Request, Response" 중 하나여야 MUST 합니다. 이러한 항목의 의미는 섹션 2.2에 정의되어 있습니다.
Reference:
유도된 구성요소를 명시하는 문서에 대한 참조, 가능하면 해당 문서를 가져올 수 있는 URI를 포함합니다.

6.4.2. 초기 내용

다음 표는 "HTTP Signature Derived Component Names" 레지스트리의 초기 내용을 포함합니다.

표 4: HTTP Signature Derived Component Names 레지스트리의 초기 내용
Name Description Status Target Reference
@signature-params 서명 베이스의 서명 매개변수 라인 예약 Active Request, Response 섹션 2.3 of RFC 9421
@method HTTP 요청 메서드 Active Request 섹션 2.2.1 of RFC 9421
@authority HTTP authority 또는 대상 호스트 Active Request 섹션 2.2.3 of RFC 9421
@scheme 요청 URI의 스킴 Active Request 섹션 2.2.4 of RFC 9421
@target-uri 요청의 전체 대상 URI Active Request 섹션 2.2.2 of RFC 9421
@request-target 요청의 request target Active Request 섹션 2.2.5 of RFC 9421
@path 요청 URI의 전체 경로 Active Request 섹션 2.2.6 of RFC 9421
@query 요청 URI의 전체 쿼리 Active Request 섹션 2.2.7 of RFC 9421
@query-param 단일 명명된 쿼리 매개변수 Active Request 섹션 2.2.8 of RFC 9421
@status 응답의 상태 코드 Active Response 섹션 2.2.9 of RFC 9421

6.5. HTTP Signature Component Parameters Registry

이 문서는 여러 종류의 구성요소 식별자를 정의하며, 일부는 특정 상황에서 매개변수화되어 고유한 동작을 제공할 수 있습니다. IANA는 이러한 매개변수 이름들, 이들이 연관된 구성요소 식별자들, 그리고 이 매개변수들이 구성요소 값에 가하는 수정사항을 기록·유지하기 위해 "HTTP Signature Component Parameters"라는 새 레지스트리를 생성하고 유지합니다. 매개변수의 정의는 적용 대상(예: 특정 필드 타입, 유도된 구성요소, 또는 문맥)을 반드시 정의해야 MUST 합니다. 이 레지스트리의 초기 값들은 섹션 6.5.2에 제시되어 있습니다. 향후 할당 및 기존 할당의 수정은 Expert Review 등록 정책을 통해 이루어집니다([RFC8126]).

지정 전문가(DE)는 다음을 수행해야 합니다:

  • 이름이 섹션 6.5.1에 제시된 템플릿을 따르는지 확인합니다. 여기에는 이름의 길이가 지나치지 않으면서도 정의된 기능에 대해 고유하고 인식 가능하도록 보장하는 것이 포함됩니다.
  • 등록 시점에 알려진 다른 기존 매개변수들과의 상호작용이나 비호환성이 있다면, 그 점을 필드 정의가 충분히 규정하는지 확인합니다.
  • 매개변수가 구성요소 값을 변경하는 경우에는, 매개변수가 적용된 구성요소 식별자에 의해 정의된 구성요소 값이 대상 HTTP 메시지에서 결정론적으로 유도될 수 있는지 확인합니다.

6.5.1. Registration Template

Name:
매개변수의 이름입니다. 이름은 섹션 3.1.2에 정의된 key ABNF 규칙을 준수하는 ASCII 문자열이어야 하며, 길이는 가급적 20자를 넘지 않는 것이 SHOULD NOT 권장됩니다. 이름은 레지스트리 문맥 내에서 고유해야 MUST 합니다.
Description:
매개변수의 기능에 대한 설명입니다.
Reference:
유도된 구성요소를 명시하는 문서에 대한 참조입니다. 가능하면 해당 문서를 가져올 수 있는 URI를 포함합니다. 관련 섹션을 표시할 수도 있지만 필수는 아닙니다.

6.5.2. Initial Contents

다음 표는 "HTTP Signature Component Parameters" 레지스트리의 초기 내용을 포함합니다.

Table 5: Initial Contents of the HTTP Signature Component Parameters Registry
Name Description Reference
sf 엄격한 Structured Field 직렬화 Section 2.1.1 of RFC 9421
key Dictionary Structured Field의 단일 키 값 Section 2.1.2 of RFC 9421
bs Byte Sequence 래핑 표시자 Section 2.1.3 of RFC 9421
tr 트레일러 Section 2.1.4 of RFC 9421
req 관련된 요청 표시자 Section 2.4 of RFC 9421
name 단일 명명된 쿼리 매개변수 Section 2.2.8 of RFC 9421

7. Security Considerations

HTTP 메시지가 서명에 의해 커버(covered)되었다고 간주되려면 다음의 모든 조건이 참이어야 합니다:

  • 검증자가 해당 메시지에 대한 서명을 기대하거나 허용하고 있다.
  • 메시지에 서명이 존재한다.
  • 서명이 식별된 키 자료와 알고리즘에 대해 검증되었다.
  • 키 자료와 알고리즘이 메시지의 문맥에 적합하다.
  • 서명이 예상 시간 범위 내에 있다.
  • 서명이 예상된 내용(필수 구성요소 포함)을 커버한다.
  • covered components 목록이 메시지의 문맥에 적용 가능하다.

섹션 1.4에 나열된 애플리케이션 요구사항 정의 외에도, 다음의 보안 고려사항들은 HTTP 메시지에 대한 서명을 생성하고 검증할 때의 요구사항에 대한 논의와 문맥을 제공합니다.

7.1. 일반적 고려사항

7.1.1. 서명 검증 건너뛰기

HTTP 메시지 서명은 검증자가 서명을 검증할 때에만 보안을 제공합니다. Signature 또는 Signature-Input 필드가 없어도 서명이 첨부된 메시지는 유효한 HTTP 메시지로 남아 있기 때문에, 검증자가 검증 함수의 출력을 무시하고 메시지를 처리할 가능성이 있습니다. 이런 상황은 개발 환경에서 요구사항을 느슨하게 하거나 디버깅 중에 검증 강제를 일시적으로 중단하는 경우 등에서 발생할 수 있습니다. 이러한 일시적 중단은 정상적인(양성) 테스트에서는 탐지하기 어렵습니다. 왜냐하면 올바른 서명은 검사가 되었는지와 관계없이 항상 유효한 응답을 생성하기 때문입니다.

이를 탐지하기 위해, 검증자는 유효한 서명과 유효하지 않은 서명 모두를 사용해 테스트해야 하며, 유효하지 않은 서명이 예상대로 실패하는지 확인해야 합니다.

7.1.2. TLS의 사용

HTTP 메시지 서명을 사용한다고 해서 전송 중 정보를 보호하기 위한 TLS 또는 동등한 메커니즘의 필요성이 사라지는 것은 아닙니다. 메시지 서명은 커버된 메시지 구성요소에 대한 무결성을 제공하지만, 당사자 간 통신의 기밀성은 제공하지 않습니다.

TLS는 TLS 종단 간의 기밀성을 제공합니다. 이와 함께 TLS는 서명 데이터 자체가 공격자에게 캡처되는 것을 방지하여 서명 재사용 공격(섹션 7.2.2)을 방지하는 중요한 역할을 합니다.

TLS를 사용할 때는 [BCP195]에서 제공하는 권고사항에 따라 배포되어야 합니다.

7.2. 메시지 처리 및 선택

7.2.1. 불충분한 커버리지

서명으로 커버되지 않은 메시지의 어떤 부분도 공격자가 서명을 훼손하지 않고 변경할 수 있습니다. 공격자는 이 점을 이용해 서명으로 보호되지 않는 헤더 필드나 다른 메시지 구성요소를 삽입하거나 수정하여 메시지 처리 방식을 변경할 수 있습니다. 이렇게 변조된 메시지는 여전히 서명 검증을 통과할 수 있지만, 검증자가 메시지를 전체적으로 처리할 때 서명이 커버하지 않는 공격자가 주입한 내용이 신뢰를 훼손하고 처리 결과를 변경할 수 있습니다.

이 문제를 방지하려면, 이 명세의 적용은 가능한 한 많은 메시지 부분을 서명하도록 요구해야 합니다(애플리케이션 및 배포의 한계 내에서). 검증자는 서명된 메시지 구성요소만 신뢰해야 합니다. 또한 검증자는 메시지 처리를 계속하기 전에 민감한 서명되지 않은 부분을 제거할 수도 있습니다.

7.2.2. 서명 재재사용(Replay)

HTTP 메시지 서명은 메시지의 일부만 서명할 수 있기 때문에, 서로 다른 두 HTTP 메시지가 동일한 서명으로 검증될 수 있습니다. 극단적인 경우에는 아무 구성요소도 서명하지 않은 서명이 있을 수 있습니다. 그런 서명이 도청되면 공격자는 이를 아무 메시지에나 붙여 마음대로 재사용할 수 있습니다. 충분한 구성요소를 커버하더라도, 특정 서명이 유사한 두 메시지에 적용될 수 있어 공격자가 서명을 유지한 채로 메시지를 재사용할 수 있습니다.

이러한 공격을 방지하려면, 먼저 서명자가 다른 메시지들과 구별되도록 메시지의 충분한 부분을 커버해야 합니다. 또한 서명은 nonce 서명 매개변수를 사용하여 메시지별 고유 값을 제공함으로써 검증자가 같은 nonce 값의 반복을 감지해 서명 자체의 재재사용을 탐지할 수 있게 해야 합니다. 더불어 서명자는 서명이 생성된 시점의 타임스탬프와 서명이 만료되는 시각을 제공하여 캡처된 서명 값의 유효성을 제한할 수 있습니다.

검증자가 서명자에게 새 서명을 생성하도록 트리거하려면 Accept-Signature 헤더 필드와 새 nonce 매개변수를 보낼 수 있습니다. 단순히 서명을 재재생하는 공격자는 선택된 nonce 값으로 새 서명을 생성할 수 없습니다.

7.2.3. 메시지 구성요소 선택

HTTP 메시지 서명의 애플리케이션은 어떤 메시지 구성요소를 서명으로 커버할지 결정해야 합니다. 애플리케이션에 따라 일부 구성요소는 중계자에 의해 검증 전에 변경될 것으로 예상될 수 있습니다. 이러한 구성요소들을 커버하면, 설계상 그러한 변경은 서명을 깨뜨립니다.

그러나 본 문서는 서명할 구성요소를 결정할 때 유연성을 허용하므로, 애플리케이션은 문제가 되는 구성요소를 피하면서 서명해야 할 메시지 부분을 적절히 선택할 수 있습니다. 예를 들어 쿼리 매개변수를 다시 쓰는 웹 애플리케이션 프레임워크는 @query 유도 구성요소 대신 @query-param 유도 구성요소로 쿼리 값을 서브 인덱싱하는 방법을 선택할 수 있습니다.

일부 구성요소는 중계자에 의해 변경되는 것이 예상되며 대부분의 경우 서명해서는 안 됩니다. 예를 들어 Via 및 Forwarded 헤더 필드는 프록시나 기타 중간 장치에 의해 교체되거나 완전히 삭제될 수 있으므로, 매우 제한적이고 밀접하게 결합된 시나리오를 제외하고는 서명에 포함하지 않아야 합니다.

서명 측면을 선택할 때의 추가 고려사항은 섹션 1.4에서 논의됩니다.

7.2.4. HTTP 필드 대신 서명 매개변수 및 유도된 구성요소 선택

일부 HTTP 필드는 HTTP 서명 매개변수나 유도된 구성요소와 유사한 값과 해석을 가집니다. 대부분의 경우 비필드 대안을 서명하는 것이 더 바람직합니다. 특히 다음의 필드들은 애플리케이션이 특별히 요구하지 않는 한 보통 서명에 포함되지 않아야 합니다:

"date"
Date 헤더 필드 값은 HTTP 메시지의 타임스탬프를 나타냅니다. 그러나 서명 자체의 생성 시간은 created 서명 매개변수에 인코딩됩니다. 이 두 값은 서명과 HTTP 메시지가 생성되고 직렬화되는 방식에 따라 다를 수 있습니다. 유효한 시간 창을 위해 서명을 처리하는 애플리케이션은 이러한 계산에 created 서명 매개변수를 사용해야 합니다. 또한 애플리케이션은 Date 필드와 created 매개변수 간의 허용 가능한 편차를 제한하여 생성된 서명이 다른 HTTP 메시지에 적용되는 것을 제한할 수 있습니다. 관련 내용은 섹션 7.2.2섹션 7.2.1를 참조하세요.
"host"
Host 헤더 필드는 HTTP/1.1에 특정된 것이며, 그 기능은 섹션 2.2.3에 정의된 @authority 유도 구성요소로 대체됩니다. 다양한 HTTP 버전에서 값을 일관되게 보존하려면 애플리케이션은 항상 @authority 유도 구성요소를 사용해야 합니다. 관련 내용은 섹션 7.5.4를 참조하세요.

7.2.5. 서명 레이블

HTTP 메시지 서명 값은 Signature 및 Signature-Input 필드 값에서 고유한 레이블로 식별됩니다. 이 레이블들은 서명 값을 메시지에 첨부할 때에만 선택되며 서명 과정에서는 고려되지 않습니다. 중계자는 메시지를 처리할 때 기존 서명에 대해 레이블을 변경할 수 있습니다.

따라서 애플리케이션은 특정 레이블의 존재에 의존하거나 레이블 자체에 의미를 부여해서는 안 됩니다. 대신 추가적인 의미를 전달해야 할 경우, 해당 의미를 서명에 첨부하고 서명으로 커버되도록 하기 위해 추가 서명 매개변수를 사용할 수 있습니다. 특히 tag 매개변수는 섹션 7.2.7에서 설명된 바와 같이 애플리케이션-특정 값을 정의하는 데 사용될 수 있습니다.

7.2.6. 다중 서명 혼동

하나의 메시지에 여러 서명을 적용할 수 있기 때문에(섹션 4.3), 공격자가 캡처한 메시지에 자신의 서명을 첨부할 수 있습니다. 이 새 서명은 공격자의 키에 의해 완전히 유효할 수도 있고, 여러 이유로 유효하지 않을 수도 있습니다. 이러한 각 상황을 고려해야 합니다.

여러 유효한 서명을 처리하는 검증자는 서명자들을(서명 키로 식별됨) 모두 고려해야 합니다. 기대된 서명자들로부터 온 서명만 받아들여야 하며, 이는 서명의 암호학적 유효성과 관계없이 적용됩니다.

메시지에 대한 일련의 서명을 처리하는 검증자는 하나 이상의 서명이 유효하지 않을 때 어떻게 할지를 결정해야 합니다. 메시지가 적어도 하나의 유효한 서명을 가질 때 수용된다면, 검증자는 유효하지 않은 모든 서명을 제거한 후 메시지 처리를 계속할 수 있습니다. 반대로 검증자가 단일 유효하지 않은 서명 때문에 메시지를 거부하면, 공격자는 유효한 서명들 옆에 유효하지 않은 서명을 주입하여 서비스 거부(DoS)를 일으킬 수 있습니다.

7.2.7. 애플리케이션-특정 서명 태그 충돌

여러 애플리케이션과 프로토콜이 동일한 메시지에 동시에 HTTP 서명을 적용할 수 있습니다. 사실 이것은 많은 상황에서 바람직한 기능입니다(섹션 4.3 참조). 단순한 검증자는 여러 서명을 처리하는 동안 혼동되어 관련 없거나 무관한 서명을 근거로 메시지를 수락하거나 거부할 수 있습니다. 애플리케이션이 자체 처리에 적용되는 서명을 선택하도록 돕기 위해, 애플리케이션은 섹션 2.3에 정의된 tag 서명 매개변수에 대해 특정 값을 선언할 수 있습니다. 예를 들어 애플리케이션 게이트웨이를 대상으로 하는 서명은 해당 애플리케이션을 위한 서명 매개변수로 tag="app-gateway"를 요구할 수 있습니다.

tag 매개변수의 사용은 공격자가 동일한 값을 타깃 애플리케이션으로도 사용할 수 없게 하지는 않습니다. 매개변수 값은 공개적이고 별다른 제한이 없기 때문입니다. 따라서 검증자는 서명을 검사할 대상을 제한하기 위해 tag 값을 사용할 수는 있지만, 각 서명은 섹션 7.2.1에서 논의된 바와 같이 충분한 커버리지가 제공되는지 확인하기 위해 개별적으로 검사되어야 합니다.

7.2.8. 메시지 콘텐츠

이 명세 자체만으로는 요청이나 응답의 HTTP 메시지 콘텐츠를 서명으로 직접 커버하지 않습니다. 그러나 [DIGEST]는 콘텐츠의 암호학적 다이제스트를 필드로 표현할 수 있는 필드 집합을 정의합니다. 이 필드가 생성되면, 섹션 2.1에 정의된 다른 필드처럼 서명 베이스에 포함될 수 있습니다.

예를 들어 다음과 같은 응답 메시지에서:

HTTP/1.1 200 OK
Content-Type: application/json

{"hello": "world"}

콘텐츠의 다이제스트는 다음과 같이 Content-Digest 필드에 추가될 수 있습니다:

NOTE: '\' line wrapping per RFC 8792

HTTP/1.1 200 OK
Content-Type: application/json
Content-Digest: \
  sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:

{"hello": "world"}

이 필드는 기본 서명 매개변수와 함께 다른 필드들과 마찬가지로 서명 베이스에 포함될 수 있습니다:

"@status": 200
"content-digest": \
  sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
"@signature-input": ("@status" "content-digest")

여기서부터 서명 절차는 평소처럼 진행됩니다.

검증 시에는 검증자가 서명뿐만 아니라 실제로 수신된 콘텐츠에 대해 Content-Digest 필드 값 자체도 검증해야 합니다. 검증자가 이 단계를 수행하지 않으면, 공격자가 메시지 콘텐츠를 교체하면서 Content-Digest 필드 값을 그대로 두어 서명을 통과시킬 수 있습니다. 서명은 필드 값 자체만 직접 커버하므로 서명만 검사하는 것은 이러한 대체 공격에 대한 충분한 보호가 아닙니다.

[DIGEST]에서 논의된 바와 같이, Content-Digest 필드의 값은 메시지의 콘텐츠 인코딩에 의존합니다. 중계자가 콘텐츠 인코딩을 변경하면 결과적인 Content-Digest 값은 바뀌며, 이는 서명을 무효화합니다. 이런 행동을 하는 중계자는 업데이트된 Content-Digest 필드 값을 사용하여 새 서명을 적용해야 하며, 이는 섹션 4.3의 리버스 프록시 사용 사례와 유사합니다.

req 매개변수(섹션 2.4)를 사용하는 애플리케이션은 이 기능의 한계를 인식해야 합니다. 구체적으로, 클라이언트가 요청에 Content-Digest 헤더 필드와 같은 것을 포함하지 않으면, 서버는 요청의 콘텐츠를 커버하는 서명을 포함할 수 없습니다.

7.3. 암호학적 고려사항

7.3.1. 암호학 및 서명 충돌

이 문서는 자체 암호 원시(primitives)를 정의하지 않으며 대신 이러한 요소들을 정의하는 다른 명세에 의존합니다. 만약 서명 알고리즘이나 서명 베이스를 처리하는 데 사용된 키가 공격에 취약하다면, 생성된 서명도 같은 공격에 취약해집니다.

서명 시스템에 대한 일반적인 공격 중 하나는 서명 충돌을 강제하는 것입니다. 동일한 서명 값이 여러 다른 입력에 대해 성공적으로 검증되는 경우입니다. 이 명세는 HTTP 메시지와 서명된 구성요소 목록에서 서명 베이스를 재구성함으로써 작동하므로, 공격자가 그런 충돌을 효과적으로 만들기는 어렵지만 불가능하지는 않습니다. 공격자는 충돌을 효과적으로 만들기 위해 HTTP 메시지와 그 커버된 구성요소들을 조작해야 합니다.

이를 방지하려면 검증된 키와 서명 알고리즘만을 사용해 HTTP 메시지에 서명해야 합니다. "HTTP Signature Algorithms" 레지스트리는 애플리케이션이 메시지에 적용할 수 있는 신뢰할 수 있는 서명 알고리즘의 한 출처입니다.

서명 매개변수 값이나 서명 값 자체를 별도로 대체하는 것이 가능하긴 하지만, 서명 베이스 생성 알고리즘(섹션 2.5)은 항상 서명 매개변수를 서명 베이스의 마지막 값으로 결정론적 직렬화 방식으로 포함합니다. 이 단계는 서명 베이스와 서명 값을 강하게 결합하여 공격자가 서명 베이스의 일부만 부분적으로 대체하는 것을 훨씬 어렵게 만듭니다.

7.3.2. 키 탈취

서명 기반 암호 시스템의 기본 가정은 서명 키가 공격자에게 노출되지 않는다는 것입니다. 만약 메시지를 서명하는 데 사용된 키가 유출되거나 탈취되면, 공격자는 해당 키를 사용하여 자신의 서명을 생성할 수 있습니다. 따라서 서명자는 모든 서명 키 자료를 탈취, 유출 또는 공격자가 사용하지 못하도록 보호해야 합니다.

이를 완화하기 위해 서명자는 시간 경과에 따른 키 회전을 수행하여 도난당한 키의 유효 기간을 제한할 수 있습니다. 또한 키 에스크로 및 안전한 저장 시스템을 사용하여 키에 대한 공격 표면을 줄일 수 있습니다. 더 나아가 비대칭 서명 알고리즘을 사용하면 대칭 알고리즘을 사용하는 것보다 키 자료 노출의 위험이 적습니다(섹션 7.3.3 참조).

7.3.3. 대칭 암호

이 문서는 비대칭 및 대칭 암호 모두 HTTP 메시지에 적용될 수 있도록 허용합니다. 본질적으로 대칭 암호 방식은 동일한 키 자료를 서명자와 검증자가 모두 알아야 합니다. 이는 검증자가 유효한 서명을 생성할 수 있음을 의미합니다. 만약 검증자가 탈취되면 공격자는 서명자를 가장할 수 있게 됩니다.

가능한 경우 이러한 유형의 공격을 피하기 위해 비대칭 방식이나 안전한 키 협상 메커니즘을 사용해야 합니다. 대칭 방식을 사용할 때는 키 자료 배포를 전체 시스템이 보호해야 합니다. 한 가지 기법은 검증 프로세스(따라서 키 자료)를 다른 코드와 분리하는 별도의 암호 모듈을 사용하는 것이며, 이는 취약한 공격 표면을 최소화합니다. 다른 기법으로는 서명자와 검증자가 메시지마다 고유한 키를 합의할 수 있게 하는 키 유도 함수를 사용하는 방법이 있습니다.

또한 시스템에서 대칭 알고리즘을 허용하는 경우, 키 다운그레이드 공격(섹션 7.3.6)을 피하기 위해 특별한 주의가 필요합니다.

7.3.4. 키 명세 혼동

HTTP 메시지에 유효한 서명이 존재한다고 해서 그 메시지가 적절한 당사자에 의해 서명되었음을 증명하지는 않습니다. 검증자는 특정 키와 알고리즘이 해당 메시지에 적합한지 확인해야 합니다. 만약 검증자가 이러한 확인을 수행하지 않으면, 공격자는 자신의 키로 서명을 대체하여 검증자가 이를 받아들이고 처리하게 만들 수 있습니다. 이를 방지하려면 검증자는 단순히 메시지에 대해 서명이 유효한지를 확인할 뿐만 아니라, 사용된 키와 알고리즘이 이 상황에 적절한지도 확인해야 합니다.

7.3.5. 비결정적 서명 원시

RSA-PSS와 ECDSA 같은 일부 암호 원시들은 알고리즘 내에 엔트로피를 포함하므로 출력이 비결정적입니다. 이러한 알고리즘으로 여러 번 서명하면 생성되는 서명 값들이 일치하지 않습니다. 검증자가 게으른 구현을 해 새 서명을 다시 계산해 같은 값을 비교하는 방식으로 처리하면, HMAC이나 EdDSA 같은 결정론적 알고리즘에는 동작하지만 비결정적 알고리즘으로 서명된 유효한 서명은 검증하지 못합니다. 따라서 검증자는 항상 해당 알고리즘에 맞는 올바른 검증 함수를 사용해야 하며 단순 비교를 해서는 안 됩니다.

7.3.6. 키 및 알고리즘 명세 다운그레이드

이 명세를 적용하는 애플리케이션은 키 명세 다운그레이드 공격에 대비해야 합니다. 예를 들어 동일한 RSA 키가 RSA-PSS와 RSA v1.5 서명 모두에 사용될 수 있습니다. 애플리케이션이 키를 RSA-PSS에만 사용하도록 기대한다면, 더 약한 RSA 1.5 명세를 사용하는 서명은 거부해야 합니다.

다운그레이드 공격의 다른 예로는 비대칭 알고리즘(RSA-PSS 등)이 기대되는 상황에서 공격자가 대칭 알고리즘(HMAC 등)을 사용한 서명으로 대체하는 경우가 있습니다. 단순한 검증자 구현은 공개 RSA 키 값을 HMAC 검증 함수의 입력으로 사용할 수 있는데, 공개 키가 공격자에게 알려져 있으므로 공격자는 이 알려진 키에 대해 유효한 HMAC 서명을 생성할 수 있습니다. 이를 방지하려면 검증자는 키 자료와 알고리즘이 사용 목적에 적합한지 확인해야 합니다. 또한 이 명세는 런타임에 alg 서명 매개변수를 통해 알고리즘을 지정하는 것을 허용하지만, 애플리케이션은 알고리즘을 정적 구성이나 상위 프로토콜 수준에서 지정하는 등 다른 메커니즘을 사용하여 공격자가 지정된 알고리즘을 대체하는 것을 방지할 것을 권장합니다.

7.3.7. 서명 값에 대한 서명

req 매개변수(섹션 2.4)나 다중 서명(섹션 4.3)을 메시지에 적용할 때, 기존 Signature 필드의 값을 서명 값으로 포함하여 새 서명이 기존 서명의 바이트를 커버하게 할 수 있습니다. 이 관행은 원래 서명 아래의 구성요소들을 전이적으로 검증 가능한 방식으로 커버하는 것처럼 보일 수 있지만, [JACKSON2019]에서 설명된 공격들이 사용되어 관련 없는 메시지에 대해 서명 출력 값을 가장할 수 있습니다.

예를 들어, Alice는 Bob에게 서명된 요청을 보내고 Bob은 Alice의 수신 메시지에 응답하고 있다는 암호학적 증거를 포함하는 서명된 응답을 제공하고자 합니다. Mallory는 이 트래픽을 가로채 Alice가 가로채졌다는 사실을 모르게 자신의 메시지로 바꾸려 합니다.

  1. Alice는 메시지 Req_A를 만들고 자신의 개인 키 Key_A_Sign으로 서명 Sig_A를 적용합니다.
  2. Alice는 자신이 Req_A를 Bob에게 보내고 있다고 믿습니다.
  3. Mallory는 Req_A를 가로채고 이 메시지에서 Sig_A 값을 읽습니다.
  4. Mallory는 Bob에게 보낼 다른 메시지 Req_M를 생성합니다.
  5. Mallory는 자신의 서명 키 Key_M_Sign을 만들어 자신의 요청 Req_M에 대해 유효한 서명 Sig_M을 생성할 수 있도록 하되, Sig_M의 바이트 값이 정확히 Sig_A와 동일하도록 만듭니다.
  6. Mallory는 Req_MSig_M를 Bob에게 보냅니다.
  7. Bob은 Mallory의 검증 키 Key_M_VerifySig_M을 검증합니다. Bob은 자신이 Alice에게 응답하고 있다고 생각하지 않습니다.
  8. Bob은 Req_M에 대해 응답 메시지 Res_B를 생성하고 자신의 키 Key_B_Sign으로 이 메시지에 대한 서명 Sig_B을 생성합니다. Bob은 새 서명에서 Sig_M의 값을 포함하지만 요청 메시지의 다른 내용은 포함하지 않습니다.
  9. Mallory는 Bob으로부터 받은 응답 Res_B와 그 안의 서명 Sig_B을 수신하고 이를 Alice에게 재전송합니다.
  10. Alice는 Mallory로부터 받은 Res_B를 읽고 Bob의 검증 키 Key_B_VerifySig_B을 검증합니다. Alice는 자신의 원래 서명 Sig_A의 바이트를 서명 베이스에 포함시키고 해당 서명이 검증됩니다.
  11. Alice는 Bob이 자신의 메시지에 응답했다는 암호학적 증거가 있다고 믿게 되지만, 실제로 Bob은 Mallory의 악의적 요청에 응답한 것이며 Alice는 이를 알지 못합니다.

이를 완화하기 위해 Bob은 요청 메시지에서 Signature 필드만이 아니라 더 많은 부분을 서명해야 Alice의 메시지와 Mallory의 것을 더 명확히 구별할 수 있습니다. 특히 비포기(non-repudiation) 목적을 위해 이 기능을 사용하는 애플리케이션은 원래 서명에 필요했던 구성요소들이 두 번째 서명에서도 별도로 커버되도록 요구할 수 있습니다. 서명된 메시지의 경우 첫 번째 서명의 Signature-Input 필드의 커버를 요구하면 nonce나 타임스탬프 같은 고유 항목들도 두 번째 서명에 의해 충분히 커버되도록 보장할 수 있습니다.

7.4. 서명 매개변수를 대상 메시지에 일치시키기

7.4.1. 필수 메시지 매개변수의 변경

공격자는 본래 무해한 서명 매개변수나 서명된 메시지 구성요소를 변경함으로써 효과적으로 서비스를 거부할 수 있습니다. 변경된 메시지를 거부하는 것이 바람직한 동작이지만, 지속적인 서명 실패는 (1) 검증자가 시스템을 다시 작동시키기 위해 서명 검사를 끄게 만들거나(자세한 내용은 섹션 7.1.1 참조) (2) 애플리케이션이 서명된 구성요소 관련 요구사항을 최소화하게 만들 수 있습니다.

만약 이러한 실패가 애플리케이션 내에서 흔히 발생한다면, 서명자와 검증자는 자신들이 생성한 서명 베이스를 서로 비교하여 메시지의 어떤 부분이 변경되고 있는지 확인해야 합니다. 예상되는 변경이 발견되면 서명자와 검증자는 통과할 수 있는 대체 요구사항 집합에 합의할 수 있습니다. 그러나 구성요소가 공격자에 의해 변경되고 있다고 의심되는 경우에는 수정된 구성요소를 서명해야 한다는 요구사항을 제거해서는 안 됩니다.

7.4.2. 서명된 구성요소 값과 대상 메시지의 값 일치

검증자는 서명된 메시지 구성요소가 메시지 자체의 값과 일치하는지 확인해야 합니다. 예를 들어, @method 유도된 구성요소는 서명 베이스 내의 값이 이 메시지를 제시할 때 사용된 HTTP 메서드와 동일해야 함을 요구합니다. 이 명세는 검증자가 메시지에서 서명 베이스를 유도하도록 요구함으로써 이를 장려하지만, 느슨한 캐싱이나 원시 서명 베이스를 처리 서브시스템으로 전달하는 경우 하류의 검증자가 제시된 서명과 일치하지 않는 메시지를 수락하게 될 수 있습니다.

이를 방지하려면, 서명 베이스를 생성하는 구성요소는 시스템 내에서 서명자와 검증자 모두가 신뢰할 수 있는 것이어야 합니다.

7.4.3. 메시지 구성요소의 출처 및 문맥

메시지 구성요소 값을 유도하기 위한 서명 문맥에는 대상 HTTP 메시지 자체, 관련된 메시지(예: 응답을 촉발한 요청), 그리고 서명자나 검증자가 접근할 수 있는 추가 정보가 포함됩니다. 서명자와 검증자는 서명 베이스의 구성요소 값을 생성할 때 모든 정보의 출처를 신중히 고려해야 하며 신뢰할 수 없는 출처로부터 정보를 가져오지 않도록 주의해야 합니다. 그렇지 않으면 공격자는 이처럼 느슨하게 정의된 메시지 문맥을 이용해 자신의 값을 서명 베이스 문자열에 주입하여 의도된 값을 덮어쓰거나 손상시킬 수 있습니다.

예를 들어, 대부분의 상황에서 메시지의 대상 URI는 [HTTP], 섹션 7.1에 정의된 대로입니다. 그러나 들어오는 요청의 @authority를 서명해야 하는 애플리케이션이 있고, 그 처리를 수행하는 애플리케이션이 리버스 프록시 뒤에 있는 경우를 가정해 보겠습니다. 이런 애플리케이션은 @authority 값의 변경을 예상하고, 클라이언트 측에서 프록시 반대편에서 보이는 외부 대상 URI를 알도록 구성될 수 있습니다. 이 애플리케이션은 메시지 구성요소 값(예: @authority)을 유도하기 위한 대상 URI로 이 구성된 값을 사용할 것입니다. 즉 들어오는 메시지의 대상 URI 대신 구성된 값을 사용합니다.

이 접근 방식에는 문제점이 있습니다. 잘못 구성된 시스템은 시스템 내의 다른 구성요소를 대상으로 의도된 서명 요청을 수락할 수 있기 때문입니다. 이러한 시나리오에서는 중계자가 대신 자신의 서명을 추가하여 애플리케이션이 직접 검증하도록 하는 것이 대안이 될 수 있으며, 이는 섹션 4.3에서 보여준 바와 같습니다. 이 대체 접근 방식은 중계자가 보다 적극적으로 개입해야 하지만 대상 애플리케이션이 외부 구성 값을 알 필요는 덜합니다.

또 다른 예로, 섹션 2.4는 응답 메시지를 서명하고 응답을 촉발한 요청 메시지의 일부를 포함하는 방법을 정의합니다. 이 경우 구성요소 값 계산의 문맥은 단일 서명이 적용된 메시지뿐만 아니라 응답과 요청 메시지의 조합입니다. 이 기능을 위해 req 플래그는 구성요소 식별자의 값이 어떤 문맥에서 가져오는지를 서명자들이 명시적으로 표시할 수 있게 합니다. 구현체는 각 구성요소에 대해 의도된 메시지만 참조되고 있는지 확인해야 하며, 그렇지 않으면 공격자가 한 쪽 또는 다른 쪽을 조작하여 서명을 교란하려 할 수 있습니다.

7.4.4. 다중 메시지 구성요소 문맥

하나의 메시지에 존재하는 각 서명마다 메시지 구성요소 값을 유도하는 문맥이 서로 달라질 수 있습니다. 특히 프록시가 메시지를 변형하고 변형된 값에 대한 서명을 기존 서명과 함께 포함하는 경우가 그렇습니다. 예를 들어, 리버스 프록시는 서비스로 전달하는 요청에서 공용 호스트 이름을 개별 서비스 호스트의 호스트 이름으로 바꿀 수 있습니다. 클라이언트와 리버스 프록시가 모두 @authority를 커버하는 서명을 추가하면, 서비스 호스트는 요청에서 서로 다른 값을 서명한 두 개의 서명을 보게 되며 이는 메시지가 클라이언트에서 서비스 호스트로 전달되는 동안 해당 구성요소가 변경되었음을 반영합니다.

이러한 경우 내부 서비스는 보통 서명 중 하나만 검증하거나, 섹션 7.4.3에서 논의된 대로 외부 구성 정보를 사용할 수 있습니다. 그러나 두 서명 모두를 처리하는 검증자는 각 서명에 대해 서로 다른 메시지 구성요소 문맥을 사용해야 합니다. 왜냐하면 @authority 구성요소의 값은 각 서명마다 다르기 때문입니다. 이런 유형의 검증자는 수신 메시지에 대한 리버스 프록시의 문맥과 리버스 프록시로부터 오는 메시지에 대한 대상 서비스의 문맥을 모두 인지해야 합니다. 검증자는 올바른 문맥을 올바른 서명에 적용하도록 특히 주의해야 하며, 그렇지 않으면 공격자가 이러한 복잡한 구성을 이용해 검증자의 입력을 혼동시킬 수 있습니다.

이러한 검증자는 또한 서명들 간의 메시지 구성요소 문맥 차이가 예상되고 허용되는지 확인해야 합니다. 예를 들어 위의 시나리오에서 리버스 프록시는 Forwarded 헤더 필드에 원래 호스트 이름을 포함하고 @authority, forwarded, 그리고 클라이언트 항목을 Signature 필드에 서명할 수 있습니다. 검증자는 Forwarded 헤더의 호스트 이름을 사용하여 호스트 이름이 예상대로 변환되었는지 확인할 수 있습니다.

7.5. HTTP 처리

7.5.1. 유효하지 않은 HTTP 필드 이름을 유도된 구성요소 이름으로 처리하기

HTTP 필드 이름의 정의는 이름에 @ 문자의 사용을 허용하지 않습니다. 따라서 모든 유도된 구성요소 이름이 @ 문자로 시작하므로 이 네임스페이스는 완전히 분리되어야 합니다. 그러나 일부 HTTP 구현체는 HTTP 필드 이름에서 허용되는 문자를 충분히 엄격하게 검사하지 않을 수 있습니다. 이러한 구현체에서는 발신자(또는 공격자)가 @ 문자로 시작하는 헤더 필드를 주입하고 애플리케이션 코드로 전달되도록 할 수 있습니다. 이러한 유효하지 않은 헤더 필드는 유도된 메시지 내용을 덮어쓰고 임의의 값을 대체하여 공격자가 서명 충돌(섹션 7.3.1) 공격이나 다른 대체 공격(예: GET 요청의 서명을 조작된 POST 요청에 사용하는 것)을 시도할 수 있는 가능성을 제공합니다.

이를 방지하려면, 메시지 구성요소 값을 선택할 때 구성요소 이름이 @ 문자로 시작하면 이를 항상 유도된 구성요소로 처리하고 절대로 HTTP 필드로 처리해서는 안 됩니다. 구성요소 이름이 @ 문자로 시작하지 않는 경우에만 메시지의 필드에서 값을 취할 수 있습니다. 섹션 2.5에서 논의된 알고리즘은 안전한 연산 순서를 제공합니다.

7.5.2. 의미상 동등한 필드 값

서명 베이스 생성 알고리즘(섹션 2.5)은 HTTP 필드의 값을 구성요소 값으로 사용합니다. 일반적인 경우 이는 서명자와 검증자 모두에 대해 필드 값의 실제 바이트를 구성요소 값으로 취하는 것을 의미합니다. 그러나 일부 필드 값은 바이트를 변경하는 의미상 동등한 변환을 허용할 수 있습니다. 예를 들어, 어떤 필드 정의는 일부 또는 전체 값이 대소문자 구분이 없다고 선언하거나 내부 공백 문자에 대해 특별 처리를 지정할 수 있습니다. 다른 필드들은 중계자에 의해 주석 제거 같은 변환이 기대되는 경우가 있습니다. 이러한 경우 검증자는 변환된 동등 값 때문에 서명자가 사용한 바이트 값과 달라져 문제가 발생할 수 있습니다. 필드 값은 애플리케이션에 여전히 허용되지만 서명 베이스에 필요한 실제 바이트가 일치하지 않아 오류를 찾기 어렵습니다.

이러한 필드를 처리할 때 서명자와 검증자는 이러한 변환을 어떻게 처리할지 합의해야 합니다(또는 합의하지 않을지). 한 가지 옵션은 문제 있는 필드를 서명하지 않는 것이지만, 그러면 애플리케이션에 대해 충분한 서명 커버리지가 여전히 제공되는지 주의해야 합니다(섹션 7.2.1). 다른 옵션은 필드를 HTTP 메시지에 추가하기 전에 애플리케이션별 표준화(canonicalization) 값을 정의하는 것으로, 예를 들어 서명하기 전에 내부 주석을 항상 제거하거나 값을 항상 소문자로 변환하는 것입니다. 이러한 변환이 필드를 메시지에서 추출한 후가 아니라 서명 베이스 생성 알고리즘에 입력되기 전에 적용되면 서명 베이스는 여전히 메시지 내에 나타나는 필드의 바이트 값을 포함하게 됩니다. 변환이 필드에서 값을 추출한 후 서명 베이스에 추가하기 전에 적용된다면 값 치환 공격과 같은 다른 공격 표면이 생길 수 있습니다. 모든 애플리케이션별 추가 규칙은 이 명세의 범위를 벗어나며, 본질적으로 이러한 변환은 특정 애플리케이션 외부의 구현 상호운용성을 해칠 수 있습니다. 가능한 한 애플리케이션이 이러한 추가 규칙 사용을 피하는 것이 권장됩니다.

7.5.3. 구조화된 필드 값 파싱

이 명세의 여러 부분은 구조화된 필드 값([STRUCTURED-FIELDS])의 파싱에 의존합니다 — 특히 HTTP 구조화된 필드 값의 엄격한 직렬화(섹션 2.1.1), Dictionary Structured Field의 멤버 참조(섹션 2.1.2), 그리고 서명을 검증할 때 @signature-input 값을 처리하는 것(섹션 3.2)이 해당됩니다. 구조화된 필드 값은 파싱이 비교적 단순하도록 설계되었지만, 파서의 단순하거나 결함 있는 구현은 구현체에 미묘한 공격 표면을 드러낼 수 있습니다.

예를 들어, @signature-input 값의 버그가 있는 파서가 구성요소 식별자 목록 내의 문자열 값 주변에 있는 따옴표의 올바른 닫힘을 강제하지 않는다면, 공격자는 이를 이용해 메시지의 Signature-Input 필드 값을 조작하여 서명 베이스에 추가적인 내용을 주입할 수 있습니다.

이를 방지하기 위해 구현체는 서명자 측과 검증자 측 모두에서 모든 구조화된 필드 처리를 위해 완전히 준수하는 신뢰할 수 있는 파서를 사용해야 합니다.

7.5.4. HTTP 버전과 구성요소 모호성

어떤 메시지 구성요소는 HTTP 버전마다 다른 방식으로 표현됩니다. 예를 들어 요청 대상의 authority는 HTTP/1.1에서 Host 헤더 필드를 사용해 전송되지만 HTTP/2에서는 :authority 의사-헤더로 전송됩니다. 서명자가 HTTP/1.1 메시지를 보내고 Host 헤더 필드를 서명했으나 메시지가 검증자에게 도달하기 전에 HTTP/2로 변환된다면 Host 헤더 필드가 삭제될 수 있으므로 서명은 검증되지 않을 것입니다.

이런 이유로 HTTP 메시지 서명은 @authority 유도된 구성요소(섹션 2.2.3)와 같이 해당 값을 얻는 단일 방식을 정의하는 유도된 구성요소 집합을 정의합니다. 따라서 애플리케이션은 가능한 경우 이러한 유도된 구성요소를 선호해야 합니다.

7.5.5. 정규화 공격

서명 베이스 생성에 어떤 모호성이라도 있으면 공격자가 메시지의 서명을 대체하거나 깨뜨릴 수 있는 여지를 제공합니다. 일부 메시지 구성요소 값, 특히 HTTP 필드 값은 잘못된 구현으로 인해 예기치 않고 안전하지 않은 동작이 발생할 수 있습니다. 본 명세의 단순한 구현체는 필드의 단일 값을 취하여 적절한 처리를 하지 않고 구성요소 값으로 직접 사용하는 방식으로 HTTP 필드 처리를 구현할 수 있습니다.

예를 들어, obs-fold 필드 값 처리가 내부 줄 접기와 공백을 제거하지 않으면, 서명자에 의해 서명 베이스에 추가적인 개행이 도입될 수 있으며 이는 공격자가 서명 충돌(섹션 7.3.1) 공격을 수행할 수 있는 가능성을 제공합니다. 또는 여러 번 나타나는 헤더 필드가 이 명세에서 요구하는 대로 단일 문자열 값으로 결합되지 않으면 유사한 공격이 발생할 수 있습니다. 서명된 구성요소 값이 서명 베이스에 여러 번 나타나면 대체되거나 다른 방식으로 공격될 수 있습니다.

이를 방지하려면 모든 서명자와 검증자의 구현체에서 전체 필드 값 처리 알고리즘을 구현해야 합니다.

7.5.6. 리스트가 아닌 필드 값

하나의 메시지에서 HTTP 필드가 여러 번 발생하면 이러한 값들은 섹션 2.5에 설명된 대로 서명 베이스에 포함하기 위해 단일 한 줄 문자열 값으로 결합되어야 합니다. 모든 HTTP 필드가 이러한 방식으로 결합되어도 필드의 유효한 값으로 남는 것은 아닙니다. 서명 베이스를 생성할 목적상 메시지 구성요소 값은 서명 베이스 문자열에서 다시 읽어 애플리케이션에서 사용하도록 의도된 것이 아닙니다. 따라서 이러한 속성을 가진 필드에 대해 서명 베이스 생성 알고리즘을 애플리케이션의 필드 처리와 분리해서 취급하는 것이 최선의 관행으로 간주됩니다. 서명된 필드 값이 유효하지 않으면 서명된 메시지도 거부되어야 합니다.

일부 HTTP 필드가 값 내에 인용되지 않은 쉼표를 허용하는 경우, 여러 필드 값을 결합하면 두 개의 의미적으로 다른 메시지가 서명 베이스에서 동일한 한 줄을 생성하는 상황이 발생할 수 있습니다. 예를 들어, 내부 쉼표가 문법에 있는 가상의 헤더 필드를 고려해 보겠습니다. 이 헤더는 두 개의 별도 값 목록을 정의하는 데 사용됩니다:

Example-Header: value, with, lots
Example-Header: of, commas

이 헤더 필드에 대해 모든 값을 단일 필드 값으로 전송하면 단일 값 목록이 생성됩니다:

Example-Header: value, with, lots, of, commas

이 두 메시지는 서명 베이스에서 다음과 같은 라인을 생성합니다:

"example-header": value, with, lots, of, commas

두 개의 의미상 다른 입력이 서명 베이스에서 동일한 출력을 만들 수 있으므로 이러한 값들을 처리할 때 특별한 주의가 필요합니다.

특히 Set-Cookie 필드([COOKIE])는 내부 문법이 [STRUCTURED-FIELDS]에서 제공하는 List 문법에 부합하지 않습니다. 일부 부분은 인용되지 않은 쉼표를 허용하고, 여러 쿠키를 보낼 때는 보통 여러 개의 별도 필드 라인으로 전송됩니다. 동일한 메시지에 여러 Set-Cookie 필드가 전송될 때 이를 단일 라인으로 결합하고 결과를 파싱하여 사용 가능한 경우는 일반적으로 불가능합니다([HTTP], 섹션 5.3 참조). 따라서 모든 쿠키는 별도 필드 값에서 처리되어야 하며 결합되지 않아야 하고, 서명 베이스는 오직 이 목적을 위해 생성된 특수 결합 값에서 처리되어야 합니다. 쿠키 값이 유효하지 않으면 서명된 메시지는 거부되어야 합니다. 이는 섹션 7.5.7에 설명된 패딩 공격의 가능한 사례입니다.

이를 처리하기 위해 애플리케이션은 Set-Cookie와 같은 문제 있는 필드의 서명을 제한할 수 있으며, 예를 들어 단일 필드 값이 존재하고 결과가 모호하지 않을 때에만 해당 필드를 서명에 포함할 수 있습니다. 서명자가 또한 bs 매개변수를 사용하여 이러한 필드를 보호할 수 있으며, 이는 섹션 2.1.3에 설명되어 있습니다.

7.5.7. 여러 필드 값으로 인한 패딩 공격

HTTP 필드 값은 HTTP 서명 베이스에 포함되기 위해 단일 문자열 값으로 결합되어야 하므로(자세한 내용은 섹션 2.5 참조), 공격자가 특정 필드에 대해 추가 값을 주입하고 이를 검증자의 서명 베이스에 추가할 수 있습니다.

대부분의 상황에서 이는 새로운 서명 베이스 값이 서명자가 서명을 생성할 때 사용한 값과 일치하지 않으므로 서명 검증이 예상대로 실패하게 만듭니다. 그러나 이론적으로 공격자는 특정 입력을 강제하기 위해 한 필드에 쓰레기 값을 삽입하고 다른 필드에 원하는 값을 삽입하는 방식으로 시도할 수 있습니다. 이는 공격자가 기존 필드 값에 추가를 통해 메시지를 변경하는 서명 충돌(섹션 7.3.1)의 변형입니다.

이를 방지하려면 애플리케이션은 서명에서 커버된 필드의 내용을 검증하는 것 외에도 서명 자체가 검증되는지 확인해야 합니다. 이러한 보호가 있으면 공격자의 패딩 공격은 필드 값 처리기에서 거부되어 서명 충돌을 강제할 수 있는 경우에도 방지됩니다.

7.5.8. 쿼리 요소 처리의 모호성

Section 5에서 정의된 HTML 폼 매개변수 형식([HTMLURL])은 널리 배포되어 많은 애플리케이션 프레임워크에서 지원됩니다. 편의상 일부 프레임워크는 HTTP 쿼리에 있는 쿼리 매개변수와 메시지 콘텐츠 내에서 발견되는 매개변수(특히 Content-Type이 "application/x-www-form-urlencoded"인 POST 메시지의 경우)를 결합합니다. @query-param 유도된 구성요소 식별자(섹션 2.2.8에 정의됨)는 요청의 대상 URI의 쿼리 섹션에서만 값을 가져옵니다. 따라서 공격자는 서명된 쿼리 매개변수를 서명되지 않은 폼 매개변수로 가리는 방식으로 대체하거나 그 반대로 대체함으로써 쿼리 매개변수를 그림자화하거나 교체할 수 있습니다.

이를 방지하려면 애플리케이션은 서명 베이스와 애플리케이션이 사용하는 값들이 일관된 문맥에서 가져오도록 해야 합니다. 이 경우에는 대상 URI의 쿼리 구성요소에서 값을 가져오도록 해야 합니다. 또한 HTTP 요청에 콘텐츠가 있는 경우 애플리케이션은 메시지 콘텐츠도 서명해야 하며, 이에 대한 논의는 섹션 7.2.8을 참조하십시오.


8. 개인정보 고려사항

8.1. 키를 통한 식별

서명자가 동일한 키를 여러 검증자와 함께 사용하거나 하나의 검증자와 함께 시간 경과에 걸쳐 동일한 키를 사용하는 경우, 해당 키의 지속적 사용은 메시지가 전송되는 검증자 집합 전반에 걸쳐 서명자를 추적하는 데 사용될 수 있습니다. 암호 키는 기능적으로 고유하도록 설계되므로 동일한 키를 계속 사용하는 것은 여러 메시지를 서명한 동일한 당사자를 식별하는 강한 지표가 됩니다.

많은 애플리케이션에서는 이것이 바람직한 특성으로, HTTP 메시지 서명이 서명자를 검증자에게 인증하는 데 사용될 수 있게 합니다. 그러나 이는 또한 서명자가 알지 못하는 추적으로 이어질 수 있습니다. 이를 방지하기 위해 서명자는 통신하는 각 검증자마다 다른 키를 사용할 수 있습니다. 때로는 서명자가 특정 검증자에게 메시지를 보낼 때 키를 회전(rotating)할 수도 있습니다. 이러한 접근법은 필요한 다른 추적 방지 기술의 적용을 대체하지는 않습니다.

8.2. 서명은 기밀성을 제공하지 않음

HTTP 메시지 서명은 서명으로 보호된 정보에 대해 기밀성을 제공하지 않습니다. HTTP 메시지의 내용(모든 필드 값과 서명 값 자체 포함)은 메시지에 접근할 수 있는 모든 당사자에게 평문으로 드러납니다.

전송 수준에서 기밀성을 제공하려면 TLS 또는 동등한 메커니즘을 사용할 수 있으며, 이는 섹션 7.1.2에서 논의된 바와 같습니다.

8.3. 오라클(Oracles)

개발자에게 오류 조건에 대해 유용한 피드백을 제공하는 필요성과 공격자에게 추가 정보를 제공하지 않는 것 사이의 균형을 맞추는 것이 중요합니다. 예를 들어 나이브하지만 유용한 서버 구현은 리소스 요청에 필요한 키 식별자(key identifier)를 표시하려 할 수 있습니다. 누군가가 해당 키를 누가 제어하는지 알게 되면 리소스의 존재와 키로 식별된 당사자 간의 상관관계를 만들 수 있습니다. 이러한 정보에 대한 접근은 공격자가 리소스의 정당한 소유자를 추가 공격 대상으로 삼는 데 사용할 수 있습니다.

8.4. 필수 콘텐츠

이 명세의 핵심 설계 원칙은 서명으로 커버되는 모든 메시지 구성요소가 검증자가 서명 베이스를 재생성하고 서명을 검증할 수 있도록 검증자에게 제공되어야 한다는 것입니다. 결과적으로 애플리케이션이 특정 필드의 서명을 요구하면 검증자는 해당 필드의 값에 접근해야 합니다.

예를 들어, 중간 처리기가 있는 일부 복잡한 시스템에서는 프록시가 서명을 깨뜨릴까 두려워 서명을 깨지 않기 위해 메시지에서 개인정보에 민감한 정보를 제거하지 못하고 전달하는 놀라운 동작이 발생할 수 있습니다. 이 특정 상황을 완화하는 한 가지 방법은 중간자가 스스로 서명을 검증한 다음 메시지를 수정하여 개인정보 민감 정보를 제거하는 것입니다. 이 시점에서 중간자는 다음 목적지에 들어오는 서명이 검증되었음을 알리기 위해 자체 서명을 추가할 수 있으며, 이는 섹션 4.3의 예에서 보여준 바와 같습니다.

9. 참고문헌

9.1. 규범 참조

[ABNF]
Crocker, D., Ed. and P. Overell, “Augmented BNF for Syntax Specifications: ABNF”, STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008, <https://www.rfc-editor.org/info/rfc5234>.
[ASCII]
Cerf, V., “ASCII format for network interchange”, STD 80, RFC 20, DOI 10.17487/RFC0020, October 1969, <https://www.rfc-editor.org/info/rfc20>.
[FIPS186-5]
NIST, “Digital Signature Standard (DSS)”, DOI 10.6028/NIST.FIPS.186-5, February 2023, <https://doi.org/10.6028/NIST.FIPS.186-5>.
[HTMLURL]
WHATWG, “URL (Living Standard)”, January 2024, <https://url.spec.whatwg.org/>.
[HTTP/1.1]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., “HTTP/1.1”, STD 99, RFC 9112, DOI 10.17487/RFC9112, June 2022, <https://www.rfc-editor.org/info/rfc9112>.
[HTTP]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., “HTTP Semantics”, STD 97, RFC 9110, DOI 10.17487/RFC9110, June 2022, <https://www.rfc-editor.org/info/rfc9110>.
[POSIX.1]
IEEE, “The Open Group Base Specifications Issue 7, 2018 edition”, 2018, <https://pubs.opengroup.org/onlinepubs/9699919799/>.
[RFC2104]
Krawczyk, H., Bellare, M., and R. Canetti, “HMAC: Keyed-Hashing for Message Authentication”, RFC 2104, DOI 10.17487/RFC2104, February 1997, <https://www.rfc-editor.org/info/rfc2104>.
[RFC2119]
Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.
[RFC6234]
Eastlake 3rd, D. and T. Hansen, “US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)”, RFC 6234, DOI 10.17487/RFC6234, May 2011, <https://www.rfc-editor.org/info/rfc6234>.
[RFC7517]
Jones, M., “JSON Web Key (JWK)”, RFC 7517, DOI 10.17487/RFC7517, May 2015, <https://www.rfc-editor.org/info/rfc7517>.
[RFC7518]
Jones, M., “JSON Web Algorithms (JWA)”, RFC 7518, DOI 10.17487/RFC7518, May 2015, <https://www.rfc-editor.org/info/rfc7518>.
[RFC8017]
Moriarty, K., Ed., Kaliski, B., Jonsson, J., and A. Rusch, “PKCS #1: RSA Cryptography Specifications Version 2.2”, RFC 8017, DOI 10.17487/RFC8017, November 2016, <https://www.rfc-editor.org/info/rfc8017>.
[RFC8032]
Josefsson, S. and I. Liusvaara, “Edwards-Curve Digital Signature Algorithm (EdDSA)”, RFC 8032, DOI 10.17487/RFC8032, January 2017, <https://www.rfc-editor.org/info/rfc8032>.
[RFC8174]
Leiba, B., “Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words”, BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[STRUCTURED-FIELDS]
Nottingham, M. and P-H. Kamp, “Structured Field Values for HTTP”, RFC 8941, DOI 10.17487/RFC8941, February 2021, <https://www.rfc-editor.org/info/rfc8941>.
[URI]
Berners-Lee, T., Fielding, R., and L. Masinter, “Uniform Resource Identifier (URI): Generic Syntax”, STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, <https://www.rfc-editor.org/info/rfc3986>.

9.2. 참고 문헌(정보)

[AWS-SIGv4]
Amazon Simple Storage Service, “Authenticating Requests (AWS Signature Version 4)”, 2006년 3월, <https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html>.
[BCP195]
Moriarty, K. and S. Farrell, “Deprecating TLS 1.0 and TLS 1.1”, BCP 195, RFC 8996, DOI 10.17487/RFC8996, 2021년 3월.
Sheffer, Y., Saint-Andre, P., and T. Fossati, “Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)”, BCP 195, RFC 9325, DOI 10.17487/RFC9325, 2022년 11월.
<https://www.rfc-editor.org/info/bcp195>
[CLIENT-CERT]
Campbell, B. and M. Bishop, “Client-Cert HTTP Header Field”, RFC 9440, DOI 10.17487/RFC9440, 2023년 7월, <https://www.rfc-editor.org/info/rfc9440>.
[COOKIE]
Barth, A., “HTTP State Management Mechanism”, RFC 6265, DOI 10.17487/RFC6265, 2011년 4월, <https://www.rfc-editor.org/info/rfc6265>.
[DIGEST]
Polli, R. and L. Pardue, “Digest Fields”, RFC 9530, DOI 10.17487/RFC9530, 2024년 2월, <https://www.rfc-editor.org/info/rfc9530>.
[JACKSON2019]
Jackson, D., Cremers, C., Cohn-Gordon, K., and R. Sasse, “Seems Legit: Automated Analysis of Subtle Attacks on Protocols that Use Signatures”, DOI 10.1145/3319535.3339813, CCS '19: Proceedings of the 2019 ACM SIGSAC Conference on Computer and Communications Security, pp. 2165-2180, 2019년 11월, <https://dl.acm.org/doi/10.1145/3319535.3339813>.
[JWS]
Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS)”, RFC 7515, DOI 10.17487/RFC7515, 2015년 5월, <https://www.rfc-editor.org/info/rfc7515>.
[RFC7239]
Petersson, A. and M. Nilsson, “Forwarded HTTP Extension”, RFC 7239, DOI 10.17487/RFC7239, 2014년 6월, <https://www.rfc-editor.org/info/rfc7239>.
[RFC7468]
Josefsson, S. and S. Leonard, “Textual Encodings of PKIX, PKCS, and CMS Structures”, RFC 7468, DOI 10.17487/RFC7468, 2015년 4월, <https://www.rfc-editor.org/info/rfc7468>.
[RFC7807]
Nottingham, M. and E. Wilde, “Problem Details for HTTP APIs”, RFC 7807, DOI 10.17487/RFC7807, 2016년 3월, <https://www.rfc-editor.org/info/rfc7807>.
[RFC8126]
Cotton, M., Leiba, B., and T. Narten, “Guidelines for Writing an IANA Considerations Section in RFCs”, BCP 26, RFC 8126, DOI 10.17487/RFC8126, 2017년 6월, <https://www.rfc-editor.org/info/rfc8126>.
[RFC8792]
Watsen, K., Auerswald, E., Farrel, A., and Q. Wu, “Handling Long Lines in Content of Internet-Drafts and RFCs”, RFC 8792, DOI 10.17487/RFC8792, 2020년 6월, <https://www.rfc-editor.org/info/rfc8792>.
[RFC9457]
Nottingham, M., Wilde, E., and S. Dalal, “Problem Details for HTTP APIs”, RFC 9457, DOI 10.17487/RFC9457, 2023년 7월, <https://www.rfc-editor.org/info/rfc9457>.
[SIGNING-HTTP-MESSAGES]
Cavage, M. and M. Sporny, “Signing HTTP Messages”, Work in Progress, draft-cavage-http-signatures-12, 작업 중 문서, 2019년 10월, <https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12>.
[SIGNING-HTTP-REQS-OAUTH]
Richer, J., Ed., Bradley, J., and H. Tschofenig, “A Method for Signing HTTP Requests for OAuth”, Work in Progress, draft-ietf-oauth-signed-http-request-03, 작업 중 문서, 2016년 8월, <https://datatracker.ietf.org/doc/html/draft-ietf-oauth-signed-http-request-03>.
[TLS]
Rescorla, E., “The Transport Layer Security (TLS) Protocol Version 1.3”, RFC 8446, DOI 10.17487/RFC8446, 2018년 8월, <https://www.rfc-editor.org/info/rfc8446>.

부록 A. HTTP 메시지 서명 감지

과거에 서명된 HTTP 메시지를 만들려는 여러 시도가 있었고, 이 명세에서 사용하는 Signature 필드의 비표준 정의들도 포함됩니다. 이 명세나 다른 발표된 문서, 또는 과거 초안 버전을 지원하려는 개발자는 불일치로 인해 예상치 못한 문제가 발생할 수 있으므로 신중하고 의도적으로 작업하는 것이 권장됩니다.

구현자는 먼저 이 명세에서 정의한 Signature-Input 필드를 감지하고 검증하여 이 문서에 설명된 메커니즘이 사용되고 있는지, 대체 메커니즘이 사용되고 있지 않은지를 확인하는 것이 권장됩니다. Signature-Input 필드가 존재하면 모든 Signature 필드는 이 명세의 문맥에서 구문 분석되고 해석될 수 있습니다.


부록 B. 예제

다음의 비규범적 예제들은 HTTP 메시지 서명의 구현을 테스트하기 위한 수단으로 제공됩니다. 주어진 서명된 메시지들은 명시된 매개변수로 서명 베이스를 생성하고, 명시된 알고리즘과 키를 사용하여 서명을 생성하는 데 사용할 수 있습니다.

제공된 개인 키는 서명을 생성하는 데 사용될 수 있지만, 일부 데모 알고리즘은 비결정적이므로 서명 결과는 예제의 정확한 바이트와 다를 수 있습니다. 제공된 공개 키는 모든 서명된 예제를 검증하는 데 사용될 수 있습니다.

B.1. 예제 키

이 섹션은 문서 전반의 예제 서명에서 참조되는 암호 키들을 제공합니다. 이 키들은 테스트 목적 이외의 용도로 절대 사용해서는 안 됩니다(MUST NOT).

각 키의 키 식별자는 이 명세의 예제 전반에서 사용됩니다. 이 예제들에서는 서명자와 검증자가 여기 사용된 모든 키 식별자를 명확히 역참조할 수 있고, 사용된 키와 알고리즘이 서명이 제시되는 문맥에 적합하다고 가정합니다.

PEM 형식의 각 개인 키 구성요소는 다음 OpenSSL 명령을 실행하여 표시할 수 있습니다([RFC7468]):

openssl pkey -text

이 명령은 OpenSSL 버전 1.1.1m으로 테스트되었습니다. 일부 시스템은 이러한 키들을 직접 생성하거나 사용하지 못할 수 있으며 추가 처리가 필요할 수 있습니다. 모든 키는 JWK 형식으로도 제공됩니다.

B.1.1. 예제 RSA 키

다음 키는 2048비트 RSA 공개/개인 키 쌍으로, 문서에서 test-key-rsa로 언급됩니다. 이 키는 PEM 형식으로 인코딩되었고 암호화되지 않았습니다.

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAhAKYdtoeoy8zcAcR874L8cnZxKzAGwd7v36APp7Pv6Q2jdsPBRrw
WEBnez6d0UDKDwGbc6nxfEXAy5mbhgajzrw3MOEt8uA5txSKobBpKDeBLOsdJKFq
MGmXCQvEG7YemcxDTRPxAleIAgYYRjTSd/QBwVW9OwNFhekro3RtlinV0a75jfZg
kne/YiktSvLG34lw2zqXBDTC5NHROUqGTlML4PlNZS5Ri2U4aCNx2rUPRcKIlE0P
uKxI4T+HIaFpv8+rdV6eUgOrB2xeI1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZSFlQ
PSXSfBDiUGhwOw76WuSSsf1D4b/vLoJ10wIDAQAB
-----END RSA PUBLIC KEY-----

-----BEGIN RSA PRIVATE KEY-----
MIIEqAIBAAKCAQEAhAKYdtoeoy8zcAcR874L8cnZxKzAGwd7v36APp7Pv6Q2jdsP
BRrwWEBnez6d0UDKDwGbc6nxfEXAy5mbhgajzrw3MOEt8uA5txSKobBpKDeBLOsd
JKFqMGmXCQvEG7YemcxDTRPxAleIAgYYRjTSd/QBwVW9OwNFhekro3RtlinV0a75
jfZgkne/YiktSvLG34lw2zqXBDTC5NHROUqGTlML4PlNZS5Ri2U4aCNx2rUPRcKI
lE0PuKxI4T+HIaFpv8+rdV6eUgOrB2xeI1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZ
SFlQPSXSfBDiUGhwOw76WuSSsf1D4b/vLoJ10wIDAQABAoIBAG/JZuSWdoVHbi56
vjgCgkjg3lkO1KrO3nrdm6nrgA9P9qaPjxuKoWaKO1cBQlE1pSWp/cKncYgD5WxE
CpAnRUXG2pG4zdkzCYzAh1i+c34L6oZoHsirK6oNcEnHveydfzJL5934egm6p8DW
+m1RQ70yUt4uRc0YSor+q1LGJvGQHReF0WmJBZHrhz5e63Pq7lE0gIwuBqL8SMaA
yRXtK+JGxZpImTq+NHvEWWCu09SCq0r838ceQI55SvzmTkwqtC+8AT2zFviMZkKR
Qo6SPsrqItxZWRty2izawTF0Bf5S2VAx7O+6t3wBsQ1sLptoSgX3QblELY5asI0J
YFz7LJECgYkAsqeUJmqXE3LP8tYoIjMIAKiTm9o6psPlc8CrLI9CH0UbuaA2JCOM
cCNq8SyYbTqgnWlB9ZfcAm/cFpA8tYci9m5vYK8HNxQr+8FS3Qo8N9RJ8d0U5Csw
DzMYfRghAfUGwmlWj5hp1pQzAuhwbOXFtxKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1
mwJ5AL0pYF0G7x81prlARURwHo0Yf52kEw1dxpx+JXER7hQRWQki5/NsUEtv+8RT
qn2m6qte5DXLyn83b1qRscSdnCCwKtKWUug5q2ZbwVOCJCtmRwmnP131lWRYfj67
B/xJ1ZA6X3GEf4sNReNAtaucPEelgR2nsN0gKQKBiGoqHWbK1qYvBxX2X3kbPDkv
9C+celgZd2PW7aGYLCHq7nPbmfDV0yHcWjOhXZ8jRMjmANVR/eLQ2EfsRLdW69bn
f3ZD7JS1fwGnO3exGmHO3HZG+6AvberKYVYNHahNFEw5TsAcQWDLRpkGybBcxqZo
81YCqlqidwfeO5YtlO7etx1xLyqa2NsCeG9A86UjG+aeNnXEIDk1PDK+EuiThIUa
/2IxKzJKWl1BKr2d4xAfR0ZnEYuRrbeDQYgTImOlfW6/GuYIxKYgEKCFHFqJATAG
IxHrq1PDOiSwXd2GmVVYyEmhZnbcp8CxaEMQoevxAta0ssMK3w6UsDtvUvYvF22m
qQKBiD5GwESzsFPy3Ga0MvZpn3D6EJQLgsnrtUPZx+z2Ep2x0xc5orneB5fGyF1P
WtP+fG5Q6Dpdz3LRfm+KwBCWFKQjg7uTxcjerhBWEYPmEMKYwTJF5PBG9/ddvHLQ
EQeNC8fHGg4UXU8mhHnSBt3EA10qQJfRDs15M38eG2cYwB1PZpDHScDnDA0=
-----END RSA PRIVATE KEY-----

동일한 공개 및 개인 키 쌍의 JWK 형식:

NOTE: '\' line wrapping per RFC 8792

{
  "kty": "RSA",
  "kid": "test-key-rsa",
  "p": "sqeUJmqXE3LP8tYoIjMIAKiTm9o6psPlc8CrLI9CH0UbuaA2JCOMcCNq8Sy\
  YbTqgnWlB9ZfcAm_cFpA8tYci9m5vYK8HNxQr-8FS3Qo8N9RJ8d0U5CswDzMYfRgh\
  AfUGwmlWj5hp1pQzAuhwbOXFtxKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1mw",
  "q": "vSlgXQbvHzWmuUBFRHAejRh_naQTDV3GnH4lcRHuFBFZCSLn82xQS2_7xFO\
  qfabqq17kNcvKfzdvWpGxxJ2cILAq0pZS6DmrZlvBU4IkK2ZHCac_XfWVZFh-PrsH\
  _EnVkDpfcYR_iw1F40C1q5w8R6WBHaew3SAp",
  "d": "b8lm5JZ2hUduLnq-OAKCSODeWQ7Uqs7eet2bqeuAD0_2po-PG4qhZoo7VwF\
  CUTWlJan9wqdxiAPlbEQKkCdFRcbakbjN2TMJjMCHWL5zfgvqhmgeyKsrqg1wSce9\
  7J1_Mkvn3fh6CbqnwNb6bVFDvTJS3i5FzRhKiv6rUsYm8ZAdF4XRaYkFkeuHPl7rc\
  -ruUTSAjC4GovxIxoDJFe0r4kbFmkiZOr40e8RZYK7T1IKrSvzfxx5AjnlK_OZOTC\
  q0L7wBPbMW-IxmQpFCjpI-yuoi3FlZG3LaLNrBMXQF_lLZUDHs77q3fAGxDWwum2h\
  KBfdBuUQtjlqwjQlgXPsskQ",
  "e": "AQAB",
  "qi": "PkbARLOwU_LcZrQy9mmfcPoQlAuCyeu1Q9nH7PYSnbHTFzmiud4Hl8bIXU\
  9a0_58blDoOl3PctF-b4rAEJYUpCODu5PFyN6uEFYRg-YQwpjBMkXk8Eb39128ctA\
  RB40Lx8caDhRdTyaEedIG3cQDXSpAl9EOzXkzfx4bZxjAHU9mkMdJwOcMDQ",
  "dp": "aiodZsrWpi8HFfZfeRs8OS_0L5x6WBl3Y9btoZgsIeruc9uZ8NXTIdxaM6\
  FdnyNEyOYA1VH94tDYR-xEt1br1ud_dkPslLV_Aac7d7EaYc7cdkb7oC9t6sphVg0\
  dqE0UTDlOwBxBYMtGmQbJsFzGpmjzVgKqWqJ3B947li2U7t63HXEvKprY2w",
  "dq": "b0DzpSMb5p42dcQgOTU8Mr4S6JOEhRr_YjErMkpaXUEqvZ3jEB9HRmcRi5\
  Gtt4NBiBMiY6V9br8a5gjEpiAQoIUcWokBMAYjEeurU8M6JLBd3YaZVVjISaFmdty\
  nwLFoQxCh6_EC1rSywwrfDpSwO29S9i8Xbaap",
  "n": "hAKYdtoeoy8zcAcR874L8cnZxKzAGwd7v36APp7Pv6Q2jdsPBRrwWEBnez6\
  d0UDKDwGbc6nxfEXAy5mbhgajzrw3MOEt8uA5txSKobBpKDeBLOsdJKFqMGmXCQvE\
  G7YemcxDTRPxAleIAgYYRjTSd_QBwVW9OwNFhekro3RtlinV0a75jfZgkne_YiktS\
  vLG34lw2zqXBDTC5NHROUqGTlML4PlNZS5Ri2U4aCNx2rUPRcKIlE0PuKxI4T-HIa\
  Fpv8-rdV6eUgOrB2xeI1dSFFn_nnv5OoZJEIB-VmuKn3DCUcCZSFlQPSXSfBDiUGh\
  wOw76WuSSsf1D4b_vLoJ10w"
}

B.1.2. 예제 RSA-PSS 키

다음 키는 2048비트 RSA 공개/개인 키 쌍으로, 문서에서 test-key-rsa-pss로 언급됩니다. 이 키는 PKCS #8 PEM 형식으로 인코딩되었고 암호화되지 않았습니다.

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr4tmm3r20Wd/PbqvP1s2
+QEtvpuRaV8Yq40gjUR8y2Rjxa6dpG2GXHbPfvMs8ct+Lh1GH45x28Rw3Ry53mm+
oAXjyQ86OnDkZ5N8lYbggD4O3w6M6pAvLkhk95AndTrifbIFPNU8PPMO7OyrFAHq
gDsznjPFmTOtCEcN2Z1FpWgchwuYLPL+Wokqltd11nqqzi+bJ9cvSKADYdUAAN5W
Utzdpiy6LbTgSxP7ociU4Tn0g5I6aDZJ7A8Lzo0KSyZYoA485mqcO0GVAdVw9lq4
aOT9v6d+nb4bnNkQVklLQ3fVAvJm+xdDOp9LCNCN48V2pnDOkFV6+U9nV5oyc6XI
2wIDAQAB
-----END PUBLIC KEY-----

-----BEGIN PRIVATE KEY-----
MIIEvgIBADALBgkqhkiG9w0BAQoEggSqMIIEpgIBAAKCAQEAr4tmm3r20Wd/Pbqv
P1s2+QEtvpuRaV8Yq40gjUR8y2Rjxa6dpG2GXHbPfvMs8ct+Lh1GH45x28Rw3Ry5
3mm+oAXjyQ86OnDkZ5N8lYbggD4O3w6M6pAvLkhk95AndTrifbIFPNU8PPMO7Oyr
FAHqgDsznjPFmTOtCEcN2Z1FpWgchwuYLPL+Wokqltd11nqqzi+bJ9cvSKADYdUA
AN5WUtzdpiy6LbTgSxP7ociU4Tn0g5I6aDZJ7A8Lzo0KSyZYoA485mqcO0GVAdVw
9lq4aOT9v6d+nb4bnNkQVklLQ3fVAvJm+xdDOp9LCNCN48V2pnDOkFV6+U9nV5oy
c6XI2wIDAQABAoIBAQCUB8ip+kJiiZVKF8AqfB/aUP0jTAqOQewK1kKJ/iQCXBCq
pbo360gvdt05H5VZ/RDVkEgO2k73VSsbulqezKs8RFs2tEmU+JgTI9MeQJPWcP6X
aKy6LIYs0E2cWgp8GADgoBs8llBq0UhX0KffglIeek3n7Z6Gt4YFge2TAcW2WbN4
XfK7lupFyo6HHyWRiYHMMARQXLJeOSdTn5aMBP0PO4bQyk5ORxTUSeOciPJUFktQ
HkvGbym7KryEfwH8Tks0L7WhzyP60PL3xS9FNOJi9m+zztwYIXGDQuKM2GDsITeD
2mI2oHoPMyAD0wdI7BwSVW18p1h+jgfc4dlexKYRAoGBAOVfuiEiOchGghV5vn5N
RDNscAFnpHj1QgMr6/UG05RTgmcLfVsI1I4bSkbrIuVKviGGf7atlkROALOG/xRx
DLadgBEeNyHL5lz6ihQaFJLVQ0u3U4SB67J0YtVO3R6lXcIjBDHuY8SjYJ7Ci6Z6
vuDcoaEujnlrtUhaMxvSfcUJAoGBAMPsCHXte1uWNAqYad2WdLjPDlKtQJK1diCm
rqmB2g8QE99hDOHItjDBEdpyFBKOIP+NpVtM2KLhRajjcL9Ph8jrID6XUqikQuVi
4J9FV2m42jXMuioTT13idAILanYg8D3idvy/3isDVkON0X3UAVKrgMEne0hJpkPL
FYqgetvDAoGBAKLQ6JZMbSe0pPIJkSamQhsehgL5Rs51iX4m1z7+sYFAJfhvN3Q/
OGIHDRp6HjMUcxHpHw7U+S1TETxePwKLnLKj6hw8jnX2/nZRgWHzgVcY+sPsReRx
NJVf+Cfh6yOtznfX00p+JWOXdSY8glSSHJwRAMog+hFGW1AYdt7w80XBAoGBAImR
NUugqapgaEA8TrFxkJmngXYaAqpA0iYRA7kv3S4QavPBUGtFJHBNULzitydkNtVZ
3w6hgce0h9YThTo/nKc+OZDZbgfN9s7cQ75x0PQCAO4fx2P91Q+mDzDUVTeG30mE
t2m3S0dGe47JiJxifV9P3wNBNrZGSIF3mrORBVNDAoGBAI0QKn2Iv7Sgo4T/XjND
dl2kZTXqGAk8dOhpUiw/HdM3OGWbhHj2NdCzBliOmPyQtAr770GITWvbAI+IRYyF
S7Fnk6ZVVVHsxjtaHy1uJGFlaZzKR4AGNaUTOJMs6NadzCmGPAxNQQOCqoUjn4XR
rOjr9w349JooGXhOxbu8nOxX
-----END PRIVATE KEY-----

동일한 공개 및 개인 키 쌍의 JWK 형식:

NOTE: '\' line wrapping per RFC 8792

{
  "kty": "RSA",
  "kid": "test-key-rsa-pss",
  "p": "5V-6ISI5yEaCFXm-fk1EM2xwAWekePVCAyvr9QbTlFOCZwt9WwjUjhtKRus\
  i5Uq-IYZ_tq2WRE4As4b_FHEMtp2AER43IcvmXPqKFBoUktVDS7dThIHrsnRi1U7d\
  HqVdwiMEMe5jxKNgnsKLpnq-4NyhoS6OeWu1SFozG9J9xQk",
  "q": "w-wIde17W5Y0Cphp3ZZ0uM8OUq1AkrV2IKauqYHaDxAT32EM4ci2MMER2nI\
  UEo4g_42lW0zYouFFqONwv0-HyOsgPpdSqKRC5WLgn0VXabjaNcy6KhNPXeJ0Agtq\
  diDwPeJ2_L_eKwNWQ43RfdQBUquAwSd7SEmmQ8sViqB628M",
  "d": "lAfIqfpCYomVShfAKnwf2lD9I0wKjkHsCtZCif4kAlwQqqW6N-tIL3bdOR-\
  VWf0Q1ZBIDtpO91UrG7pansyrPERbNrRJlPiYEyPTHkCT1nD-l2isuiyGLNBNnFoK\
  fBgA4KAbPJZQatFIV9Cn34JSHnpN5-2ehreGBYHtkwHFtlmzeF3yu5bqRcqOhx8lk\
  YmBzDAEUFyyXjknU5-WjAT9DzuG0MpOTkcU1EnjnIjyVBZLUB5Lxm8puyq8hH8B_E\
  5LNC-1oc8j-tDy98UvRTTiYvZvs87cGCFxg0LijNhg7CE3g9piNqB6DzMgA9MHSOw\
  cElVtfKdYfo4H3OHZXsSmEQ",
  "e": "AQAB",
  "qi": "jRAqfYi_tKCjhP9eM0N2XaRlNeoYCTx06GlSLD8d0zc4ZZuEePY10LMGWI\
  6Y_JC0CvvvQYhNa9sAj4hFjIVLsWeTplVVUezGO1ofLW4kYWVpnMpHgAY1pRM4kyz\
  o1p3MKYY8DE1BA4KqhSOfhdGs6Ov3Dfj0migZeE7Fu7yc7Fc",
  "dp": "otDolkxtJ7Sk8gmRJqZCGx6GAvlGznWJfibXPv6xgUAl-G83dD84YgcNGn\
  oeMxRzEekfDtT5LVMRPF4_AoucsqPqHDyOdfb-dlGBYfOBVxj6w-xF5HE0lV_4J-H\
  rI63Od9fTSn4lY5d1JjyCVJIcnBEAyiD6EUZbUBh23vDzRcE",
  "dq": "iZE1S6CpqmBoQDxOsXGQmaeBdhoCqkDSJhEDuS_dLhBq88FQa0UkcE1QvO\
  K3J2Q21VnfDqGBx7SH1hOFOj-cpz45kNluB832ztxDvnHQ9AIA7h_HY_3VD6YPMNR\
  VN4bfSYS3abdLR0Z7jsmInGJ9X0_fA0E2tkZIgXeas5EFU0M",
  "n": "r4tmm3r20Wd_PbqvP1s2-QEtvpuRaV8Yq40gjUR8y2Rjxa6dpG2GXHbPfvM\
  s8ct-Lh1GH45x28Rw3Ry53mm-oAXjyQ86OnDkZ5N8lYbggD4O3w6M6pAvLkhk95An\
  dTrifbIFPNU8PPMO7OyrFAHqgDsznjPFmTOtCEcN2Z1FpWgchwuYLPL-Wokqltd11\
  nqqzi-bJ9cvSKADYdUAAN5WUtzdpiy6LbTgSxP7ociU4Tn0g5I6aDZJ7A8Lzo0KSy\
  ZYoA485mqcO0GVAdVw9lq4aOT9v6d-nb4bnNkQVklLQ3fVAvJm-xdDOp9LCNCN48V\
  2pnDOkFV6-U9nV5oyc6XI2w"
}

B.1.3. 예제 ECC P-256 테스트 키

다음 키는 곡선 P-256 위의 공개/개인 타원곡선 키 쌍으로, 문서에서 test-key-ecc-p256로 언급됩니다. 이 키는 PEM 형식으로 인코딩되었고 암호화되지 않았습니다.

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqIVYZVLCrPZHGHjP17CTW0/+D9Lf
w0EkjqF7xB4FivAxzic30tMM4GF+hR6Dxh71Z50VGGdldkkDXZCnTNnoXQ==
-----END PUBLIC KEY-----

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFKbhfNZfpDsW43+0+JjUr9K+bTeuxopu653+hBaXGA7oAoGCCqGSM49
AwEHoUQDQgAEqIVYZVLCrPZHGHjP17CTW0/+D9Lfw0EkjqF7xB4FivAxzic30tMM
4GF+hR6Dxh71Z50VGGdldkkDXZCnTNnoXQ==
-----END EC PRIVATE KEY-----

동일한 공개 및 개인 키 쌍의 JWK 형식:

{
  "kty": "EC",
  "crv": "P-256",
  "kid": "test-key-ecc-p256",
  "d": "UpuF81l-kOxbjf7T4mNSv0r5tN67Gim7rnf6EFpcYDs",
  "x": "qIVYZVLCrPZHGHjP17CTW0_-D9Lfw0EkjqF7xB4FivA",
  "y": "Mc4nN9LTDOBhfoUeg8Ye9WedFRhnZXZJA12Qp0zZ6F0"
}

B.1.4. 예제 Ed25519 테스트 키

다음 키는 Edwards 곡선 ed25519 위의 타원곡선 키로, 문서에서 test-key-ed25519로 언급됩니다. 이 키는 PKCS #8 PEM 형식으로 인코딩되었고 암호화되지 않았습니다.

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=
-----END PUBLIC KEY-----

-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF
-----END PRIVATE KEY-----

동일한 공개 및 개인 키 쌍의 JWK 형식:

{
  "kty": "OKP",
  "crv": "Ed25519",
  "kid": "test-key-ed25519",
  "d": "n4Ni-HpISpVObnQMW0wOhCKROaIKqKtW_2ZYb2p9KcU",
  "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
}

B.1.5. 예제 공유 비밀

다음의 공유 비밀은 Base64로 인코딩된 64바이트의 무작위로 생성된 값이며, 문서에서 test-shared-secret로 언급됩니다:

NOTE: '\' line wrapping per RFC 8792

uzvJfB4u3N0Jy4T7NZ75MDVcr8zSTInedJtkgcu46YW4XByzNJjxBdtjUkdJPBt\
  bmHhIDi6pcl8jsasjlTMtDQ==

B.2. 테스트 사례

이 절은 구현의 정확성을 검증하기 위한 테스트 사례로 사용할 수 있는 비규범적 예제를 제공합니다. 다음 HTTP 메시지를 기반으로 한 예제들입니다:

요청의 경우, 이 test-request 메시지가 사용됩니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Digest: sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+T\
  aPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
Content-Length: 18

{"hello": "world"}

응답의 경우, 이 test-response 메시지가 사용됩니다:

NOTE: '\' line wrapping per RFC 8792

HTTP/1.1 200 OK
Date: Tue, 20 Apr 2021 02:07:56 GMT
Content-Type: application/json
Content-Digest: sha-512=:mEWXIS7MaLRuGgxOBdODa3xqM1XdEvxoYhvlCFJ41Q\
  JgJc4GTsPp29l5oGX69wWdXymyU0rjJuahq4l5aGgfLQ==:
Content-Length: 23

{"message": "good dog"}

B.2.1. rsa-pss-sha512를 사용한 최소 서명

이 예제는 test-request에 대해 rsa-pss-sha512 알고리즘을 사용한 최소 서명을 제시합니다. HTTP 메시지의 구성요소는 전혀 커버하지 않지만, 서명자가 제공한 nonce와 함께 키 소유를 증명하는 타임스탬프 서명을 제공합니다.

해당 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@signature-params": ();created=1618884473;keyid="test-key-rsa-pss"\
  ;nonce="b3k2pp5k7z-50gnwp.yemd"

이로 인해 서명 레이블 sig-b21 아래 메시지에 다음과 같은 Signature-Input 및 Signature 헤더 필드가 추가됩니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig-b21=();created=1618884473\
  ;keyid="test-key-rsa-pss";nonce="b3k2pp5k7z-50gnwp.yemd"
Signature: sig-b21=:d2pmTvmbncD3xQm8E9ZV2828BjQWGgiwAaw5bAkgibUopem\
  LJcWDy/lkbbHAve4cRAtx31Iq786U7it++wgGxbtRxf8Udx7zFZsckzXaJMkA7ChG\
  52eSkFxykJeNqsrWH5S+oxNFlD4dzVuwe8DhTSja8xxbR/Z2cOGdCbzR72rgFWhzx\
  2VjBqJzsPLMIQKhO4DGezXehhWwE56YCE+O6c0mKZsfxVrogUvA4HELjVKWmAvtl6\
  UnCh8jYzuVG5WSb/QEVPnP5TmcAnLH1g+s++v6d4s8m0gCw1fV5/SITLq9mhho8K3\
  +7EPYTU8IU1bLhdxO5Nyt8C8ssinQ98Xw9Q==:

커버된 구성요소 목록이 비어 있기 때문에, 이 서명은 공격자가 관련 없는 HTTP 메시지에 적용할 수도 있다는 점에 유의하십시오. 이 예제에서는 동일한 서명의 재재생을 방지하기 위해 nonce 매개변수를 포함하지만, 공격자가 서명을 가로채 검증자에게 전달되지 못하게 하면 공격자는 이 서명을 다른 메시지에 적용할 수 있습니다. 따라서 비어 있는 커버 구성요소 집합의 사용은 권장되지 않습니다. 자세한 논의는 섹션 7.2.1을 참조하십시오.

여기서 사용된 RSA-PSS 알고리즘은 비결정적이므로 알고리즘을 실행할 때마다 서로 다른 서명 값이 생성됩니다. 제공된 서명 값은 주어진 키로 검증될 수 있으나 새로 생성된 서명 값이 예제와 일치할 것으로 기대해서는 안 됩니다. 자세한 내용은 섹션 7.3.5를 참조하십시오.

B.2.2. rsa-pss-sha512를 사용한 선택적 구성요소 커버

이 예제는 test-request에서 추가 구성요소(권한(@authority), Content-Digest 헤더 필드, 그리고 단일 명명된 쿼리 매개변수)를 rsa-pss-sha512 알고리즘으로 커버합니다. 또한 애플리케이션-특정 값인 header-example을 가진 tag 매개변수를 추가합니다.

해당 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@authority": example.com
"content-digest": sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX\
  +TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
"@query-param";name="Pet": dog
"@signature-params": ("@authority" "content-digest" \
  "@query-param";name="Pet")\
  ;created=1618884473;keyid="test-key-rsa-pss"\
  ;tag="header-example"

이로 인해 레이블 sig-b22 아래 메시지에 다음과 같은 Signature-Input 및 Signature 헤더 필드가 추가됩니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig-b22=("@authority" "content-digest" \
  "@query-param";name="Pet");created=1618884473\
  ;keyid="test-key-rsa-pss";tag="header-example"
Signature: sig-b22=:LjbtqUbfmvjj5C5kr1Ugj4PmLYvx9wVjZvD9GsTT4F7GrcQ\
  EdJzgI9qHxICagShLRiLMlAJjtq6N4CDfKtjvuJyE5qH7KT8UCMkSowOB4+ECxCmT\
  8rtAmj/0PIXxi0A0nxKyB09RNrCQibbUjsLS/2YyFYXEu4TRJQzRw1rLEuEfY17SA\
  RYhpTlaqwZVtR8NV7+4UKkjqpcAoFqWFQh62s7Cl+H2fjBSpqfZUJcsIk4N6wiKYd\
  4je2U/lankenQ99PZfB4jY3I5rSV2DSBVkSFsURIjYErOs0tFTQosMTAoxk//0RoK\
  UqiYY8Bh0aaUEb0rQl3/XaVe4bXTugEjHSw==:

여기서 사용된 RSA-PSS 알고리즘은 비결정적이므로 알고리즘을 실행할 때마다 서로 다른 서명 값이 생성됩니다. 제공된 서명 값은 주어진 키로 검증될 수 있으나 새로 생성된 서명 값이 예제와 일치할 것으로 기대해서는 안 됩니다. 자세한 내용은 섹션 7.3.5를 참조하십시오.

B.2.3. rsa-pss-sha512를 사용한 전체 커버리지

이 예제는 test-request의 모든 적용 가능한 메시지 구성요소(콘텐츠 타입 및 길이 포함)와 많은 유도된 구성요소들을 커버합니다. 다시 rsa-pss-sha512 알고리즘을 사용합니다. Host 헤더 필드는 @authority 유도 구성요소가 포함되어 있으므로 커버되지 않았다는 점에 유의하십시오.

해당 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"date": Tue, 20 Apr 2021 02:07:55 GMT
"@method": POST
"@path": /foo
"@query": ?param=Value&Pet=dog
"@authority": example.com
"content-type": application/json
"content-digest": sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX\
  +TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
"content-length": 18
"@signature-params": ("date" "@method" "@path" "@query" \
  "@authority" "content-type" "content-digest" "content-length")\
  ;created=1618884473;keyid="test-key-rsa-pss"

이로 인해 레이블 sig-b23 아래 메시지에 다음과 같은 Signature-Input 및 Signature 헤더 필드가 추가됩니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig-b23=("date" "@method" "@path" "@query" \
  "@authority" "content-type" "content-digest" "content-length")\
  ;created=1618884473;keyid="test-key-rsa-pss"
Signature: sig-b23=:bbN8oArOxYoyylQQUU6QYwrTuaxLwjAC9fbY2F6SVWvh0yB\
  iMIRGOnMYwZ/5MR6fb0Kh1rIRASVxFkeGt683+qRpRRU5p2voTp768ZrCUb38K0fU\
  xN0O0iC59DzYx8DFll5GmydPxSmme9v6ULbMFkl+V5B1TP/yPViV7KsLNmvKiLJH1\
  pFkh/aYA2HXXZzNBXmIkoQoLd7YfW91kE9o/CCoC1xMy7JA1ipwvKvfrs65ldmlu9\
  bpG6A9BmzhuzF8Eim5f8ui9eH8LZH896+QIF61ka39VBrohr9iyMUJpvRX2Zbhl5Z\
  JzSRxpJyoEZAFL2FUo5fTIztsDZKEgM4cUA==:

이 예제에서 Date 헤더 필드의 값과 created 서명 매개변수의 값은 동일할 필요가 없습니다. 이는 Date 헤더 필드가 HTTP 메시지를 생성할 때 추가되고 created 매개변수는 해당 메시지에 대한 서명을 생성할 때 채워지므로 두 시간이 서로 다를 수 있기 때문입니다. Date 헤더 필드가 서명으로 커버되는 경우, 그 값이 created 매개변수의 값과 일치해야 하는지는 검증자가 결정해야 합니다. 자세한 논의는 섹션 7.2.4를 참조하십시오.

여기서 사용된 RSA-PSS 알고리즘은 비결정적이므로 알고리즘을 실행할 때마다 서로 다른 서명 값이 생성됩니다. 제공된 서명 값은 주어진 키로 검증될 수 있으나 새로 생성된 서명 값이 예제와 일치할 것으로 기대해서는 안 됩니다. 자세한 내용은 섹션 7.3.5를 참조하십시오.

B.2.4. ecdsa-p256-sha256를 사용한 응답 서명

이 예제는 test-response 메시지의 일부를 ecdsa-p256-sha256 알고리즘과 키 test-key-ecc-p256로 커버합니다.

해당 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@status": 200
"content-type": application/json
"content-digest": sha-512=:mEWXIS7MaLRuGgxOBdODa3xqM1XdEvxoYhvlCFJ4\
  1QJgJc4GTsPp29l5oGX69wWdXymyU0rjJuahq4l5aGgfLQ==:
"content-length": 23
"@signature-params": ("@status" "content-type" "content-digest" \
  "content-length");created=1618884473;keyid="test-key-ecc-p256"

이로 인해 레이블 sig-b24 아래 메시지에 다음과 같은 Signature-Input 및 Signature 헤더 필드가 추가됩니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig-b24=("@status" "content-type" \
  "content-digest" "content-length");created=1618884473\
  ;keyid="test-key-ecc-p256"
Signature: sig-b24=:wNmSUAhwb5LxtOtOpNa6W5xj067m5hFrj0XQ4fvpaCLx0NK\
  ocgPquLgyahnzDnDAUy5eCdlYUEkLIj+32oiasw==:

여기서 사용된 ECDSA 서명 알고리즘은 비결정적이므로 알고리즘을 실행할 때마다 서로 다른 서명 값이 생성됩니다. 제공된 서명 값은 주어진 키로 검증될 수 있으나 새로 생성된 서명 값이 예제와 일치할 것으로 기대해서는 안 됩니다. 자세한 내용은 섹션 7.3.5를 참조하십시오.

B.2.5. hmac-sha256를 사용한 요청 서명

이 예제는 test-request 메시지의 일부를 hmac-sha256 알고리즘과 비밀 test-shared-secret으로 커버합니다.

해당 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"date": Tue, 20 Apr 2021 02:07:55 GMT
"@authority": example.com
"content-type": application/json
"@signature-params": ("date" "@authority" "content-type")\
  ;created=1618884473;keyid="test-shared-secret"

이로 인해 레이블 sig-b25 아래 메시지에 다음과 같은 Signature-Input 및 Signature 헤더 필드가 추가됩니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig-b25=("date" "@authority" "content-type")\
  ;created=1618884473;keyid="test-shared-secret"
Signature: sig-b25=:pxcQw6G3AjtMBQjwo8XzkZf/bws5LelbaMk5rGIGtE8=:

대칭 서명을 실무에 사용하기 전에 보안 트레이드오프에 대한 논의를 섹션 7.3.3에서 확인하십시오.

B.2.6. ed25519를 사용한 요청 서명

이 예제는 test-request 메시지의 일부를 Ed25519 알고리즘과 키 test-key-ed25519로 커버합니다.

해당 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"date": Tue, 20 Apr 2021 02:07:55 GMT
"@method": POST
"@path": /foo
"@authority": example.com
"content-type": application/json
"content-length": 18
"@signature-params": ("date" "@method" "@path" "@authority" \
  "content-type" "content-length");created=1618884473\
  ;keyid="test-key-ed25519"

이로 인해 레이블 sig-b26 아래 메시지에 다음과 같은 Signature-Input 및 Signature 헤더 필드가 추가됩니다:

NOTE: '\' line wrapping per RFC 8792

Signature-Input: sig-b26=("date" "@method" "@path" "@authority" \
  "content-type" "content-length");created=1618884473\
  ;keyid="test-key-ed25519"
Signature: sig-b26=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1\
  u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:

B.3. TLS 종료 프록시

이 예제에서는 리소스 앞에 TLS 종료 리버스 프록시가 위치합니다. 클라이언트는 요청에 서명하지 않고 대신 상호 TLS로 호출합니다. 종료 프록시는 TLS 스트림을 검증하고 [CLIENT-CERT]에 따라 Client-Cert 헤더 필드로 클라이언트의 TLS 인증서를 주입한 다음 이 필드에 서명을 적용합니다. 이 헤더 필드를 서명함으로써 리버스 프록시는 초기 요청의 TLS 매개변수를 자체적으로 검증했음을 증명할 뿐만 아니라 클라이언트의 동작과 독립적으로 백엔드 시스템에 자신을 인증할 수 있습니다.

클라이언트는 상호 TLS를 사용하여 TLS 종료 프록시에게 다음 요청을 보냅니다:

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: example.com
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Length: 18

{"hello": "world"}

프록시는 TLS 연결을 처리하고 클라이언트의 TLS 인증서를 Client-Cert 헤더 필드로 추출하여 service.internal.example에 호스팅된 내부 서비스로 전달합니다. 이로 인해 다음과 같은 서명되지 않은 요청이 생성됩니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: service.internal.example
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Length: 18
Client-Cert: :MIIBqDCCAU6gAwIBAgIBBzAKBggqhkjOPQQDAjA6MRswGQYDVQQKD\
  BJMZXQncyBBdXRoZW50aWNhdGUxGzAZBgNVBAMMEkxBIEludGVybWVkaWF0ZSBDQT\
  AeFw0yMDAxMTQyMjU1MzNaFw0yMTAxMjMyMjU1MzNaMA0xCzAJBgNVBAMMAkJDMFk\
  wEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8YnXXfaUgmnMtOXU/IncWalRhebrXmck\
  C8vdgJ1p5Be5F/3YC8OthxM4+k1M6aEAEFcGzkJiNy6J84y7uzo9M6NyMHAwCQYDV\
  R0TBAIwADAfBgNVHSMEGDAWgBRm3WjLa38lbEYCuiCPct0ZaSED2DAOBgNVHQ8BAf\
  8EBAMCBsAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0RAQH/BBMwEYEPYmRjQGV\
  4YW1wbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIBHda/r1vaL6G3VliL4/Di6YK0Q6\
  bMjeSkC3dFCOOB8TAiEAx/kHSB4urmiZ0NX5r5XarmPk0wmuydBVoU4hBVZ1yhk=:

{"hello": "world"}

서명이 없으면 내부 서비스는 수신된 연결이 올바른 정보를 포함하고 있다고 신뢰해야 합니다. 프록시가 Client-Cert 헤더 필드 및 내부 요청의 다른 부분에 서명함으로써 내부 서비스는 신뢰할 수 있는 프록시가 요청을 처리하여 적절한 서비스에 전달했음을 확신할 수 있습니다. 프록시의 서명 베이스는 다음과 같습니다:

NOTE: '\' line wrapping per RFC 8792

"@path": /foo
"@query": ?param=Value&Pet=dog
"@method": POST
"@authority": service.internal.example
"client-cert": :MIIBqDCCAU6gAwIBAgIBBzAKBggqhkjOPQQDAjA6MRswGQYDVQQKD\
  BJMZXQncyBBdXRoZW50aWNhdGUxGzAZBgNVBAMMEkxBIEludGVybWVkaWF0ZSBD\
  QTAeFw0yMDAxMTQyMjU1MzNaFw0yMTAxMjMyMjU1MzNaMA0xCzAJBgNVBAMMAkJDM\
  FkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8YnXXfaUgmnMtOXU/IncWalRhebrXm\
  ckC8vdgJ1p5Be5F/3YC8OthxM4+k1M6aEAEFcGzkJiNy6J84y7uzo9M6NyMHAwCQY\
  DVR0TBAIwADAfBgNVHSMEGDAWgBRm3WjLa38lbEYCuiCPct0ZaSED2DAOBgNVHQ8B\
  Af8EBAMCBsAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0RAQH/BBMwEYEPYmRjQ\
  GV4YW1wbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIBHda/r1vaL6G3VliL4/Di6YK0\
  Q6bMjeSkC3dFCOOB8TAiEAx/kHSB4urmiZ0NX5r5XarmPk0wmuydBVoU4hBVZ1yhk=:
"@signature-params": ("@path" "@query" "@method" "@authority" \
  "client-cert");created=1618884473;keyid="test-key-ecc-p256"

이로 인해 다음과 같은 서명이 생성됩니다:

NOTE: '\' line wrapping per RFC 8792

xVMHVpawaAC/0SbHrKRs9i8I3eOs5RtTMGCWXm/9nvZzoHsIg6Mce9315T6xoklyy0y\
zhD9ah4JHRwMLOgmizw==

이 서명은 프록시에서 내부 서비스로 전송되는 다음의 서명된 요청을 생성하며, 프록시의 서명은 레이블 ttrp 아래에 포함됩니다:

NOTE: '\' line wrapping per RFC 8792

POST /foo?param=Value&Pet=dog HTTP/1.1
Host: service.internal.example
Date: Tue, 20 Apr 2021 02:07:55 GMT
Content-Type: application/json
Content-Length: 18
Client-Cert: :MIIBqDCCAU6gAwIBAgIBBzAKBggqhkjOPQQDAjA6MRswGQYDVQQKD\
  BJMZXQncyBBdXRoZW50aWNhdGUxGzAZBgNVBAMMEkxBIEludGVybWVkaWF0ZSBDQT\
  AeFw0yMDAxMTQyMjU1MzNaFw0yMTAxMjMyMjU1MzNaMA0xCzAJBgNVBAMMAkJDMFk\
  wEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8YnXXfaUgmnMtOXU/IncWalRhebrXmck\
  C8vdgJ1p5Be5F/3YC8OthxM4+k1M6aEAEFcGzkJiNy6J84y7uzo9M6NyMHAwCQYDV\
  R0TBAIwADAfBgNVHSMEGDAWgBRm3WjLa38lbEYCuiCPct0ZaSED2DAOBgNVHQ8BAf\
  8EBAMCBsAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0RAQH/BBMwEYEPYmRjQGV\
  4YW1wbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIBHda/r1vaL6G3VliL4/Di6YK0Q6\
  bMjeSkC3dFCOOB8TAiEAx/kHSB4urmiZ0NX5r5XarmPk0wmuydBVoU4hBVZ1yhk=:
Signature-Input: ttrp=("@path" "@query" "@method" "@authority" \
  "client-cert");created=1618884473;keyid="test-key-ecc-p256"
Signature: ttrp=:xVMHVpawaAC/0SbHrKRs9i8I3eOs5RtTMGCWXm/9nvZzoHsIg6\
  Mce9315T6xoklyy0yzhD9ah4JHRwMLOgmizw==:

{"hello": "world"}

내부 서비스는 프록시의 서명을 검증할 수 있으므로 클라이언트의 인증서가 적절히 처리되었음을 신뢰할 수 있습니다.

B.4. HTTP 메시지 변환

HTTP는 중계자와 애플리케이션이 메시지의 의미론을 변경하지 않으면서 HTTP 메시지를 변환할 수 있도록 허용합니다. HTTP 메시지 서명은 다양한 상황에서 이러한 변환에 대해 강건하도록 설계되었습니다.

예를 들어, 다음 HTTP 요청 메시지는 Ed25519 알고리즘과 키 test-key-ed25519로 서명되었습니다:

NOTE: '\' line wrapping per RFC 8792

GET /demo?name1=Value1&Name2=value2 HTTP/1.1
Host: example.org
Date: Fri, 15 Jul 2022 14:24:55 GMT
Accept: application/json
Accept: */*
Signature-Input: transform=("@method" "@path" "@authority" \
  "accept");created=1618884473;keyid="test-key-ed25519"
Signature: transform=:ZT1kooQsEHpZ0I1IjCqtQppOmIqlJPeo7DHR3SoMn0s5J\
  Z1eRGS0A+vyYP9t/LXlh5QMFFQ6cpLt2m0pmj3NDA==:

이 메시지의 서명 베이스 문자열은 다음과 같습니다:

"@method": GET
"@path": /demo
"@authority": example.org
"accept": application/json, */*
"@signature-params": ("@method" "@path" "@authority" "accept")\
  ;created=1618884473;keyid="test-key-ed25519"

다음 메시지는 Accept-Language 헤더 필드 추가 및 쿼리 매개변수 추가로 변경되었습니다. 그러나 Accept-Language 헤더 필드나 쿼리가 서명에 포함되지 않으므로 동일한 서명이 여전히 유효합니다:

NOTE: '\' line wrapping per RFC 8792

GET /demo?name1=Value1&Name2=value2&param=added HTTP/1.1
Host: example.org
Date: Fri, 15 Jul 2022 14:24:55 GMT
Accept: application/json
Accept: */*
Accept-Language: en-US,en;q=0.5
Signature-Input: transform=("@method" "@path" "@authority" \
  "accept");created=1618884473;keyid="test-key-ed25519"
Signature: transform=:ZT1kooQsEHpZ0I1IjCqtQppOmIqlJPeo7DHR3SoMn0s5J\
  Z1eRGS0A+vyYP9t/LXlh5QMFFQ6cpLt2m0pmj3NDA==:

다음 메시지는 Date 헤더 필드 제거, Referer 헤더 필드 추가, 그리고 Accept 헤더 필드의 단일 라인으로의 병합으로 변경되었습니다. Date와 Referer 헤더 필드는 서명에 포함되지 않으며 Accept 헤더 필드의 병합은 HTTP 필드 값의 정규화 알고리즘으로 이미 허용된 변환입니다. 동일한 서명이 여전히 유효합니다:

NOTE: '\' line wrapping per RFC 8792

GET /demo?name1=Value1&Name2=value2 HTTP/1.1
Host: example.org
Referer: https://developer.example.org/demo
Accept: application/json, */*
Signature-Input: transform=("@method" "@path" "@authority" \
  "accept");created=1618884473;keyid="test-key-ed25519"
Signature: transform=:ZT1kooQsEHpZ0I1IjCqtQppOmIqlJPeo7DHR3SoMn0s5J\
  Z1eRGS0A+vyYP9t/LXlh5QMFFQ6cpLt2m0pmj3NDA==:

다음 메시지는 원래 메시지의 필드 값 순서를 변경했지만 개별 Accept 헤더 필드의 순서는 변경하지 않았습니다. 동일한 서명이 여전히 유효합니다:

NOTE: '\' line wrapping per RFC 8792

GET /demo?name1=Value1&Name2=value2 HTTP/1.1
Accept: application/json
Accept: */*
Date: Fri, 15 Jul 2022 14:24:55 GMT
Host: example.org
Signature-Input: transform=("@method" "@path" "@authority" \
  "accept");created=1618884473;keyid="test-key-ed25519"
Signature: transform=:ZT1kooQsEHpZ0I1IjCqtQppOmIqlJPeo7DHR3SoMn0s5J\
  Z1eRGS0A+vyYP9t/LXlh5QMFFQ6cpLt2m0pmj3NDA==:

다음 메시지는 메서드를 POST로 변경하고 authority를 Host 헤더 필드의 "example.com"으로 변경했습니다. 메서드와 authority가 모두 서명에 포함되어 있기 때문에 동일한 서명은 더 이상 유효하지 않습니다:

NOTE: '\' line wrapping per RFC 8792

POST /demo?name1=Value1&Name2=value2 HTTP/1.1
Host: example.com
Date: Fri, 15 Jul 2022 14:24:55 GMT
Accept: application/json
Accept: */*
Signature-Input: transform=("@method" "@path" "@authority" \
  "accept");created=1618884473;keyid="test-key-ed25519"
Signature: transform=:ZT1kooQsEHpZ0I1IjCqtQppOmIqlJPeo7DHR3SoMn0s5J\
  Z1eRGS0A+vyYP9t/LXlh5QMFFQ6cpLt2m0pmj3NDA==:

다음 메시지는 동일한 이름을 가진 두 Accept 헤더 필드의 순서를 변경했습니다. 동일한 이름을 가진 필드들의 순서는 HTTP에서 의미론적으로 중요하므로 서명 베이스에서 사용되는 값이 변경되어 동일한 서명은 더 이상 유효하지 않습니다:

NOTE: '\' line wrapping per RFC 8792

GET /demo?name1=Value1&Name2=value2 HTTP/1.1
Host: example.org
Date: Fri, 15 Jul 2022 14:24:55 GMT
Accept: */*
Accept: application/json
Signature-Input: transform=("@method" "@path" "@authority" \
  "accept");created=1618884473;keyid="test-key-ed25519"
Signature: transform=:ZT1kooQsEHpZ0I1IjCqtQppOmIqlJPeo7DHR3SoMn0s5J\
  Z1eRGS0A+vyYP9t/LXlh5QMFFQ6cpLt2m0pmj3NDA==:

감사의 글

이 명세는 초기에는 [SIGNING-HTTP-MESSAGES]를 기반으로 했습니다. 편집자들은 해당 인터넷 초안의 저자인 Mark Cavage와 Manu Sporny에게 그들의 작업과 지속적인 기여에 대해 감사드립니다. 이 명세에는 또한 [SIGNING-HTTP-REQS-OAUTH] 및 유사한 다른 노력들의 기여도 포함되어 있습니다.

편집자들은 또한 다음 개인들에게(알파벳 순서) 이 문서와 그 전신들에 대한 피드백, 통찰 및 구현에 대해 감사를 표합니다: Mark Adamcin, Mark Allen, Paul Annesley, Karl Böhlmark, Stéphane Bortzmeyer, Sarven Capadisli, Liam Dennehy, Stephen Farrell, Phillip Hallam-Baker, Tyler Ham, Eric Holmes, Andrey Kislyuk, Adam Knight, Dave Lehn, Ilari Liusvaara, Dave Longley, James H. Manger, Kathleen Moriarty, Yoav Nir, Mark Nottingham, Adrian Palmer, Lucas Pardue, Roberto Polli, Julian Reschke, Michael Richardson, Wojciech Rygielski, Rich Salz, Adam Scarr, Cory J. Slep, Dirk Stein, Henry Story, Lukasz Szewc, Chris Webber, and Jeffrey Yasskin.


저자 연락처

Annabelle Backman (editor)
Amazon
P.O. Box 81226
Seattle, WA 98108-1226
United States of America
EMail: richanna@amazon.com
URI: https://www.amazon.com/
Justin Richer (editor)
Bespoke Engineering
EMail: ietf@justin.richer.org
URI: https://bspk.io/
Manu Sporny
Digital Bazaar
203 Roanoke Street W.
Blacksburg, VA 24060
United States of America
EMail: msporny@digitalbazaar.com