インターネット技術タスクフォース (IETF) A. Backman, Editor
Request for Comments: 9421 Amazon
カテゴリ: Standards Track J. Richer, Editor
ISSN: 2070-1721 Bespoke Engineering
M. Sporny
Digital Bazaar
2024年2月

HTTP メッセージ署名


概要

本書は、HTTP メッセージの構成要素に対してデジタル署名またはメッセージ認証コードを作成、エンコード、および検証するためのメカニズムを説明します。本メカニズムは、署名者が完全な HTTP メッセージを知らない場合や、メッセージが検証者に届く前に(中継者によって例えば変換されるなど)変換される可能性があるユースケースをサポートします。また、本書は進行中の HTTP 交換において、後続の HTTP メッセージに署名を適用するよう要求する手段についても説明します。

このメモの状態

これはインターネット標準トラック文書です。

本書はインターネット技術タスクフォース (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 の利用が非現実的である(例えばブラウザが提示するクライアント証明書の扱いなど)か、メッセージ真正性を提供するために必要な機能が使えないことがあります。さらに、アプリケーションによっては、HTTP メッセージに対して TLS 証明書とは別のアプリケーション固有の上位レベル鍵を結び付ける必要がある場合があります。そのため、TLS は多くの HTTP ベースのアプリケーションの要件を満たせる一方で、普遍的な解決策ではありません。

加えて、多くのアプリケーションは、ライブラリ、プロキシ、アプリケーションフレームワークが署名時や検証時にメッセージの一部を変更または隠すため、ワイヤ上で見える HTTP メッセージの完全な情報を持たないまま署名の生成や検証を行う必要があります。こうしたアプリケーションは、レイヤリングや抽象化を侵害せずに、アプリケーションにとって最も重要なメッセージ部分を保護する手段を必要とします。

最後に、JSON Web Signature のようなオブジェクトベースの署名メカニズム [JWS] は、署名された正確な情報が完全な形で伝達されることを要求します。これらを HTTP メッセージに適用する際、HTTP メッセージの要素はオブジェクトのペイロード内に直接複製されるか、ハッシュを介して含まれる必要があり、この実践は検証時に繰り返された情報の整合性を慎重にチェックする必要があるため複雑さを導入します。

本書は、HTTP メッセージの一部構成要素に対して分離署名(detached signature)を用いることで、エンドツーエンドの完全性と真正性を提供するメカニズムを定義します。このメカニズムにより、アプリケーションはメッセージのうち意味があり適切なコンポーネントだけに対してデジタル署名または MAC を作成できます。厳密な正規化ルールにより、HTTP によって許容される多くの方法でメッセージが変換された場合でも検証者が署名を検証できるようにします。

本書で説明する署名メカニズムは三つの部分から成ります:

  • 署名ベースを作成するために使用される、さまざまなプロトコル要素やその他の HTTP メッセージコンポーネントに対する共通の命名法と正規化ルール群(Section 2)。
  • この署名ベースを用いて HTTP メッセージコンポーネントに対して署名を生成・検証するための暗号的プリミティブを適用するアルゴリズム(Section 3)。
  • 署名および関連メタデータを HTTP メッセージに付与し、付与済みの署名やメタデータを HTTP メッセージから解析するためのメカニズム。これを容易にするために、本書は "Signature-Input" および "Signature" フィールドを定義します(Section 4)。

本書はまた、"Accept-Signature" フィールドを介して、続く一つ以上のメッセージで署名の使用を交渉するメカニズムを提供します(Section 5)。この任意の交渉メカニズムは、機会的またはアプリケーション主導のメッセージ署名とともにどちらの当事者でも使用できます。

本書で定義されるメカニズムは、アプリケーション向けの総合的なセキュリティ機構を構築するための重要なツールです。このツールキットは強力な機能を提供しますが、完全なセキュリティストーリーを構築する上で十分ではありません。特に、Section 1.4 に列挙された要件や、Section 7 で論じられるセキュリティ考慮事項は、本仕様の実装者にとって非常に重要です。例えば、本仕様は HTTP メッセージ内容(RFC9110 Section 6.4 で定義)を直接カバーする手段を定義しません。代わりに、Digest 仕様 [DIGEST] によるメッセージ内容のハッシュを利用することに依存しており、これは Section 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 message", "HTTP request", "HTTP response", "target URI", "gateway", "header field", "intermediary", "request target", "trailer field", "sender", "method", および "recipient" といった用語は、[HTTP] で定義されているものとして使用します。

便宜上、本書では「署名」という語を、デジタル署名(公開鍵暗号を用いるもの)と鍵付き MAC(対称暗号を用いるもの)の両方を指すために使用します。同様に、動詞 "sign" はデジタル署名または鍵付き MAC の生成のいずれかを指します。特に公開鍵暗号による署名操作の出力を指す場合は「デジタル署名」と明示します。

本書は、データ型を指定するために RFC8941 Section 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 メッセージ署名を生成している、または生成したエンティティ。複数のエンティティが署名者として振る舞い、同一メッセージに別個の署名を付与することがあります。
Verifier:
HTTP メッセージに対する署名を検証している、または検証したエンティティ。HTTP メッセージ署名は複数回、潜在的に異なるエンティティによって検証され得ます。
HTTP Message Component:
HTTP メッセージの一部で、HTTP メッセージ署名によってカバー可能なもの。
Derived Component:
指定されたアルゴリズムや処理を用いて HTTP メッセージから導出される HTTP メッセージコンポーネント。詳細は Section 2.2 を参照。
HTTP Message Component Name:
フィールド名や導出コンポーネント名のように、HTTP メッセージコンポーネントの出所を識別する文字列。
HTTP Message Component Identifier:
HTTP メッセージコンポーネント名と任意のパラメータの組み合わせ。これは、特定の HTTP メッセージ署名およびそれが適用される HTTP メッセージに関して特定の HTTP メッセージコンポーネントを一意に識別します。
HTTP Message Component Value:
特定の HTTP メッセージにおける特定のコンポーネント識別子に関連付けられた値。コンポーネント値は HTTP メッセージから導出され、通常は正規化プロセスの対象となります。
Covered Components:
フィールド(Section 2.1)および導出コンポーネント(Section 2.2)に対する順序付けられた識別子の集合で、署名によってカバーされるメッセージコンポーネントの集合を示します。@signature-params 識別子自体は含まれません。この集合の順序は保存され、署名者と検証者の間で署名ベースの再構築を容易にするために伝達されます。
Signature Base:
署名者と検証者がカバーされたコンポーネント集合と HTTP メッセージを用いて生成するバイト列のシーケンス。署名ベースは暗号アルゴリズムによって処理され、HTTP メッセージ署名の生成または検証に用いられます。
HTTP Message Signature Algorithm:
署名と検証のプロセスを記述する暗号アルゴリズムで、HTTP_SIGN および HTTP_VERIFY プリミティブとして Section 3.3 で説明される方法で定義されます。
Key Material:
署名の生成または検証に必要な鍵素材。鍵素材は明示的な key identifier で識別されることが多く、署名者は使用した鍵を検証者に示すことができます。
Creation Time:
署名が生成された時点を署名者が主張するタイムスタンプ。
Expiration Time:
署名が検証者によってもはや受け入れられるべきでない時点を署名者が主張するタイムスタンプ。
Target Message:
HTTP メッセージ署名が適用される対象の HTTP メッセージ。
Signature Context:
HTTP メッセージコンポーネント値が取り出されるデータソース。コンテキストは対象メッセージおよび署名者または検証者が持つ追加情報(例:リクエストの完全なターゲット URI やレスポンスに関連するリクエストメッセージなど)を含み得ます。

"UNIX timestamp" という用語は、[POSIX.1] の Section 4.16 が呼ぶところの "seconds since the Epoch" を指します。

本書には部分的および完全な HTTP メッセージの非規範的な例が含まれます。いくつかの例では長い値の折り返しを示すために単一のトレーリングバックスラッシュ(\)を使用しています([RFC8792])。折り返しの行にある \ 文字および先頭の空白は値の一部ではありません。

1.2. 要件

HTTP は中継者によるメッセージ変換を許容し、場合によっては要求します。これは受信側が送信側のメッセージとビット単位で同一でないメッセージを受け取る結果をもたらす可能性があります。このような場合、受信者は送信者の生データのバイト列に対して完全性保護を検証することができません。なぜならデジタル署名や MAC の検証は、署名者と検証者がまったく同一の署名ベースを持っていることを必要とするからです。したがってメッセージの生バイト列を署名ベースの信頼できる出所として頼ることができない場合、署名者と検証者は各自のバージョンのメッセージから署名ベースを独立に作成する必要があり、そのためにはメッセージの意味を変えない安全な変更に対して回復力のあるメカニズムが必要です。

何が安全な変更であり何が安全でない変更かを厳密に定義するのは様々な理由で実用的でありません。アプリケーションは多様な方法で HTTP を使用し、特定のメッセージ内のある情報(例えばメッセージ内容、メソッド、あるいは特定のヘッダーフィールド)が重要かどうかで意見が分かれ得ます。したがって、汎用的な解決策は署名者が署名するメッセージコンポーネントをある程度制御できることを提供する必要があります。

HTTP アプリケーションは、完全な HTTP メッセージへのアクセスや制御が提供されない環境(例えばブラウザの JavaScript 環境)で動作しているか、あるいはプロトコルの詳細を抽象化するライブラリ(例:Java HTTP Client (HttpClient))を使用していることがあります。これらのアプリケーションは、HTTP メッセージの完全な情報を持たない場合でも署名の生成と検証ができる必要があります。

1.3. HTTP メッセージの変換

前述のとおり、HTTP は実装がさまざまな方法でメッセージを変換することを明示的に許可し、場合によっては要求します。実装はこれらの変換の多くに耐性を持つことが要求されます。以下は文脈を示すために提供する非規範的かつ網羅的でない変換の一覧です:

  • 異なるフィールド名を持つフィールドの順序入れ替え(RFC9110 Section 5.3)。
  • 同一フィールド名のフィールドの結合(RFC9110 Section 5.2)。
  • Connection ヘッダーに列挙されたフィールドの削除(RFC9110 Section 7.6.1)。
  • 制御オプションを示すフィールドの追加(RFC9110 Section 7.6.1)。
  • トランスファーコーディングの追加または削除(RFC9110 Section 7.7)。
  • Via(RFC9110 Section 7.6.3)や Forwarded(RFC7239 Section 4)のようなフィールドの追加。
  • HTTP バージョン間の変換(例:HTTP/1.x と HTTP/2 間の変換)。
  • フィールド名、リクエスト URI スキーム、ホストなどの大文字小文字の変化(大文字小文字非区別の要素)。
  • リクエストターゲットとオーソリティの変更であって、それらを合わせて適用してもメッセージのターゲット URI が変わらない場合の変更(RFC9110 Section 7.1 の定義に従う)。

さらに、非推奨または本来許されない変換であっても野生ではまだ発生することがあるものがあります。これらの変換は署名を破壊することなく処理可能であり、例えば次のような操作が含まれます:

  • フィールド値の先頭や末尾の空白の使用、追加、または削除。
  • フィールド値における obs-fold の使用、追加、または削除(RFC9112 Section 5.2)。

こうした種類の変換は、署名でカバーされたコンポーネントに対して行われても署名検証を妨げるべきではない変換として識別できます。さらに、署名でカバーされていないコンポーネントへのすべての変更は署名検証を妨げるべきではありません。

この種の変換の例とそれらがメッセージ署名に与える影響については、付録 B.4 を参照してください。

一方、カバーされたコンポーネントのフィールド値を解析して再直列化することや導出コンポーネントの値を変更するような変換は、署名がターゲットメッセージに対して有効でなくなる原因となり得ます。本仕様を適用するアプリケーションは、期待される変換がカバーコンポーネントの選択によって十分に扱われることを確保する必要があります。

1.4. HTTP メッセージ署名の適用

HTTP メッセージ署名は多様な状況やアプリケーションに適用できる汎用ツールとして設計されています。安全かつ適切に HTTP メッセージ署名を適用するために、あるアプリケーションまたは本仕様のプロファイルは、少なくとも次の項目を指定しなければなりません(MUST):

  • 期待され、かつカバーコンポーネントリストに含めることが要求されるコンポーネント識別子の集合(Section 2)および署名パラメータ(Section 2.3)。例えば、認可プロトコルは Authorization フィールドをカバーして認可資格情報を保護し、署名パラメータに created パラメータを含めることを要求するかもしれません。一方で、セマンティックに意味のある HTTP メッセージ内容を期待する API は、Content-Digest フィールド([DIGEST])の存在とカバーを要求し、さらに API 固有の値を持つ tag パラメータ(Section 2.3)を要求することがあります。
  • 必須または期待されるカバーコンポーネントフィールドやパラメータの Structured Field タイプ([STRUCTURED-FIELDS])。
  • 署名を検証するために使用する鍵素材を取得する手段。アプリケーションは通常、署名パラメータの keyid を使用して鍵を解決する規則を定義しますが、事前登録された署名者鍵など他の手段で適切な鍵が既知であることもあり得ます。
  • 署名者が使用することを期待する署名アルゴリズムの集合と、検証者が受け付けるアルゴリズムの集合。
  • 署名検証に用いる署名アルゴリズムが鍵素材とメッセージコンテキストに対して適切かどうか判定する手段。例えば、署名パラメータの alg によりアルゴリズムを明示する、鍵素材からアルゴリズムを導出する、あるいは事前設定されたアルゴリズムを使用する方式などが考えられます。
  • 署名に用いられた鍵とアルゴリズムがメッセージの文脈に適切であることを判定する手段。例えば ECDSA のみを期待するサーバーは RSA 署名を拒否すべきですし、公開鍵暗号を期待するサーバーは対称暗号を拒否すべきです。
  • HTTP メッセージおよびそのアプリケーション文脈からメッセージコンポーネントを導出する際の文脈を決定する手段。通常これは対象の HTTP メッセージ自体ですが、外部ホスト名など設定によって知られる追加情報を含むこともあります。
  • Section 2.4 のメカニズムを用いてリクエストとレスポンスの結び付けが必要な場合、その結び付けのプロパティを提供するために必要となるリクエストメッセージとレスポンスメッセージのすべての要素。
  • 署名が無効である、鍵素材が不適切である、有効期間が仕様外である、コンポーネント値が計算できない、または検証中にその他のエラーが発生した場合に、検証者が署名者に返すエラーメッセージとコード。例えば、署名が認証メカニズムとして用いられる場合、401(Unauthorized)や 403(Forbidden)といった HTTP ステータスコードが適切なことがあります。HTTP API の応答であれば、400(Bad Request)などのステータスコードに詳細を含めることができ、RFC7807/RFC9457 に従った問題詳細を用いて誤った鍵素材が使用されたことを示すこともできます。

これらのパラメータを選択する際、検証者が署名ベースを再現するために必要なすべての情報にアクセスできることを保証する必要があります。例えば、リバースプロキシの背後にあるサーバーは、導出コンポーネント @target-uri を利用するには元のリクエスト URI を知る必要があります(見かけ上のターゲット URI はリバースプロキシによって変更されるため)。また、レスポンスで署名を使用するアプリケーションは、クライアントが署名された部分(サーバーが req パラメータを使って署名したリクエストの部分を含む)にアクセスできることを確保する必要があります(Section 2.4参照)。

この種のプロファイリングの詳細はアプリケーションの範疇であり本仕様の範囲外ですが、いくつかの追加考慮事項はSection 7で議論されています。特に、必要なコンポーネント識別子の集合を選択する際には、カバレッジがアプリケーションに対して十分であることに注意する必要があります(Section 7.2.1 および Section 7.2.8 を参照)。本仕様はアプリケーション向けの完全なセキュリティシステムの一部のみを定義します。完全なシステムを構築する際にはセキュリティ分析を行うことが重要です。AWS Signature Version 4 [AWS-SIGv4] のような歴史的システムは適用例として参考になりますが、それらを参照したからといって HTTP メッセージ署名を用いるアプリケーションに対するセキュリティ分析の必要性が無くなるわけではありません。


2. HTTP メッセージ構成要素

署名者と検証者がどのコンポーネントが署名に含まれているかを確定できるようにするために、本書は HTTP メッセージ署名でカバーされるコンポーネントのためのコンポーネント識別子、これらの識別子に関連付けられた値を HTTP メッセージから導出し正規化する一連の規則、およびこれらの正規化済み値を署名ベースに組み合わせる手段を定義します。

これらの値を導出するための署名コンテキストは、署名者と検証者の両方がアクセス可能であることがMUSTです。コンテキストは特定の署名内のすべてのコンポーネントで同一であることがMUSTです。例えば、@query 導出コンポーネントに生のクエリ文字列を用い、同じ署名内の @query-param 導出コンポーネントに結合済みのクエリとフォームパラメータを用いるのは誤りになります。メッセージコンポーネントコンテキストに関するさらなる考慮事項は Section 7.4.3 を参照してください。

コンポーネント識別子はコンポーネント名とその名前に関連付けられた任意のパラメータで構成されます。各コンポーネント名は HTTP フィールド名(Section 2.1)か、登録された導出コンポーネント名(Section 2.2)のいずれかです。コンポーネント識別子に対する可能なパラメータは識別子に依存します。すべての可能なパラメータを一覧する "HTTP Signature Component Parameters" レジストリは Section 6.5 で定義されています。

単一のカバーされたコンポーネントリスト内では、各コンポーネント識別子は一度しか出現してはならないことがMUSTです。コンポーネント識別子は、コンポーネント名が異なるか、同じコンポーネント名に対してパラメータが異なれば別個と見なされます。同じコンポーネント名を持ちつつ、"foo";bar"foo";baz のように区別可能なパラメータで異なる識別子を含めることはMAYです。コンポーネント識別子を処理する際(検証中のパースなど)、パラメータの順序は保存されることがMUSTですが、2つのコンポーネント識別子を等価性チェックする際にはパラメータの順序は重要ではありません。つまり、"foo";bar;baz"foo";baz;bar は同じメッセージには存在できません(これらは同等であるため)が、システムが一方の形式を他方の形式に変換してはならないということです。

コンポーネント識別子に関連付けられたコンポーネント値は、その識別子自体によって定義されます。コンポーネント値は改行文字(\n)を含んではならないことがMUST NOTです。一部の HTTP メッセージコンポーネントはビット単位の値が変わっても意味が変わらない変換(例えばフィールド値の結合)が行われ得ます。したがって、メッセージコンポーネント値は署名される前に正規化される必要があり、中継者によるそのような変換があっても署名が検証できるようにします。本書は各コンポーネント識別子に対して、その関連コンポーネント値をそのような正規化形式に変換する規則を定義します。

以下の節では、コンポーネント識別子名、そのパラメータ、関連する値、および値の正規化規則を定義します。メッセージコンポーネントを署名ベースに結合する方法は Section 2.5 で定義されています。

2.1. HTTP フィールド

HTTP フィールドのコンポーネント名は、そのフィールド名の小文字化した形式です(Section 5.1 of [HTTP] に定義)。HTTP フィールド名は大文字小文字を区別しませんが、実装はコンポーネント名として小文字化したフィールド名(例:content-type, date, etag)を使用しなければなりません(MUST)。

HTTP フィールドのコンポーネント値は、対象メッセージの指定されたヘッダーフィールドから取られるフィールド値です(Section 5.5 of [HTTP])。この振る舞いは、以下に示す reqtr フラグ等の追加パラメータと規則によって上書きされない限り適用されます。多くのフィールドについて、フィールド値は [HTTP] が推奨するように ASCII 文字列であり、コンポーネント値はまさにその文字列です。実装によっては他のエンコーディングが存在し得るため、すべての非 ASCII フィールド値は署名ベースに追加される前に ASCII にエンコードされなければなりません(MUST)。問題のあるフィールド値をラップする手段としては、Section 2.1.3 で説明される bs パラメータがあります。

追加のパラメータや規則で上書きされない限り、HTTP フィールド値は Section 5.2 of [HTTP] に定義されたとおり単一の値に結合されなければなりません(MUST)。具体的には、同一フィールド名が複数回送信された場合、フィールド値は単一のカンマと単一の空白("," + " ")で連結して結合する必要があります。中継者はカンマ間で任意の量の空白を使って値を結合することが許されるため、検証者がこの点を考慮していないと署名は失敗する可能性があります。堅牢性を高めるため、署名されたメッセージはカバーされたフィールドについて可能な限り単一インスタンスのみを含めることがRECOMMENDEDです。特にリストベースのフィールドは下述の厳密アルゴリズムに従って直列化された値を単一インスタンスとして含めると、中継者による変化を避けやすくなります。単一インスタンスで送れない場合は、署名者と検証者が下記の厳密アルゴリズムに基づいてすべての個別フィールド値を取り扱い結合することがRECOMMENDEDです。フィールドが Structured Field の List または Dictionary 型である場合、この効果は Section 2.1.1 に記述される厳密な Structured Field シリアライゼーションを要求することでより直接的に達成できます。

Set-Cookie のように([COOKIE])値の結合をこの方法で行えないフィールドもある点に注意してください(複数の入力から結合した出力が一意に解釈できない場合)。コンポーネント値は署名プロセスにより解析されることはなく、署名ベースの一部としてのみ使用されますが、結合値が曖昧になり得るため、こうしたフィールドを署名に含める際は注意が必要です。問題のあるフィールドをラップする手段としては Section 2.1.3bs パラメータがあります。この問題に関する詳細は Section 7.5.6 を参照してください。

特定の実装で正しく結合された値が直接利用できない場合、次のアルゴリズムによってリストベースのフィールドに対する正規化結果を生成できます:

  1. メッセージ内の各インスタンスのフィールド値を、そのメッセージで出現する順序(または出現するであろう順序)で順序付きリストとして作成する。
  2. リスト内の各アイテムの先頭および末尾の空白を取り除く。HTTP フィールド値は先頭および末尾の空白を含めてはならないため、準拠実装ではこの操作は無効操作になります。
  3. 行内の obsolete line folding を取り除き、単一のスペース(" ")で置き換える(Section 5.2 of [HTTP/1.1] を参照)。この挙動は HTTP/1.1 固有であり、他の HTTP 版では内部折り返しを許容しない点に注意。
  4. 各アイテムの間を単一のカンマ(",")と単一のスペース(" ")で連結する。

得られた文字列がそのフィールドのコンポーネント値になります。

中継者が変える可能性のある大文字小文字の違いなど、同等の意味を持つ複数の正当な直列化が存在する HTTP フィールドがある点に注意してください。そのようなフィールドを署名および処理するアプリケーションは、署名者と検証者が同一の値を導出できるように値の扱い方を検討しなければならないことがMUSTです(詳しくは Section 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)

次の例は、これらの例示ヘッダーフィールドのコンポーネント値を Section 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)

署名ベース生成アルゴリズム(Section 2.5)によって、コロンとコンポーネント識別子の後に追加されるコロンと空白の後には空文字列値が直列化されます。

"x-empty-header":(SP)

任意の HTTP フィールドコンポーネント識別子は、特定の状況で以下のパラメータを持つことがMAYあり、各々はその詳細が別節で説明されています:

sf
Structured Field 値の厳密なエンコードでコンポーネント値が直列化されることを示すブールフラグ(Section 2.1.1)。
key
辞書型 Structured Field から単一のメンバ値を選択するために使われる文字列パラメータ(Section 2.1.2)。
bs
個々のフィールド値が Byte Sequence データ構造でエンコードされてからコンポーネント値に結合されることを示すブールフラグ(Section 2.1.3)。
req
署名されたレスポンスに対して、コンポーネント値がレスポンス自体ではなくこのレスポンスを引き起こしたリクエストから導出されることを示すブールフラグ。なお、このパラメータはリクエストをターゲットとする導出コンポーネント識別子にも適用できます(Section 2.4)。
tr
メッセージのトレーラから値が取られることを示すブールフラグ(Section 6.5 of [HTTP] に定義)。このフラグがない場合、フィールド値はヘッダーフィールドから取られます(Section 6.3 of [HTTP]、および Section 2.1.4 を参照)。

複数のパラメータを同時に指定することはMAYですが、冗長または互換性のない組み合わせもあります。例えば、key パラメータは Dictionary アイテムに対して厳密な直列化を要求するため、sf の機能は key によって既にカバーされます。生のバイトを必要とする bs パラメータは、結合後の解析されたデータ構造を必要とする sfkey と互換性がありません。

追加のパラメータは Section 6.5 で設立された "HTTP Signature Component Parameters" レジストリで定義できます。

2.1.1. HTTP 構造化フィールドの厳密な直列化

HTTP フィールドの値がアプリケーション側で Structured Field 型([STRUCTURED-FIELDS])であると判っており、その期待される型が明らかである場合、署名者はコンポーネント識別子に sf パラメータを含めることがMAYです。このパラメータが含まれる場合、HTTP フィールド値はその型に適用される Section 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)

結果の文字列がコンポーネント値として使用されます(Section 2.1 を参照)。

2.1.2. 辞書型構造化フィールドのメンバー

あるフィールドがアプリケーション側で Dictionary Structured Field であると判っている場合、その Dictionary の値内の個別メンバーは key パラメータと Dictionary メンバーキーを String 値として用いることで識別できます。

メッセージ内に複数のフィールド値が存在する場合、これらは正規化の前に単一の Dictionary 構造に結合されなければなりません(MUST)。

Dictionary Structured Field の個別メンバー値は、Section 4.1.2 の直列化アルゴリズムを member_value とそのパラメータに対して適用することで正規化されます。具体的には、値は Item または Inner List として直列化され、すべてのパラメータと可能なサブフィールドは Section 4 で定義された厳密な直列化ルールに従って直列化されます。

あるフィールドに対してパラメータ化された各キーは、署名ベース内で複数回出現してはならないことがMUST NOTです。パラメータ化されたキーは、ソース Dictionary 内での順序に関係なく、署名ベース内では任意の順序で現れてもよい(MAY)です。

もしカバー対象として指定された Dictionary キーが Dictionary 内に存在しない場合、それは署名ベース生成時にエラーを引き起こさなければなりません(MUST)。

以下は、次の例のような Dictionary であることがアプリケーションにより判っているヘッダーフィールドに対する、Dictionary メンバーの正規化済み値の非規範的な例です:

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

次の例は、このフィールドの異なるコンポーネント識別子に対する正規化済み値を、Section 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 フィールドの値が直列化に関して問題を引き起こすことがアプリケーションにより判っている場合、特に複数値を単一行に結合することで問題が生じるような場合(Section 7.5.6 参照)、署名者はコンポーネント識別子に bs パラメータを含めて、フィールド値を結合する前にバイナリ構造としてラップする必要があることを示すべきです(SHOULD)。

このパラメータがコンポーネント識別子に含まれる場合、コンポーネント値は次のアルゴリズムに従って計算されなければなりません(MUST):

  1. 入力を、メッセージ内で出現する順序のフィールド値の順序集合とする。
  2. 処理済みのフィールド値を蓄積するための空の List を作成する。
  3. 集合内の各フィールド値について:

    11.
    フィールド値の先頭および末尾の空白を取り除く(準拠実装ではこれは無効操作)。
    12.
    行内の obsolete line folding を取り除き、単一のスペース(" ")に置き換える(Section 5.2 of [HTTP/1.1] を参照)。この挙動は HTTP/1.1 固有です。
    13.
    得られたフィールド値のバイトを Byte Sequence としてエンコードする。ほとんどのフィールドは ASCII に制限されますが、一部の実装では他のオクテットが含まれる場合があります。
    14.
    Byte Sequence を List 蓄積器に追加する。
  4. 中間結果は Byte Sequence 値の List になります。
  5. Section 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 パラメータが追加されると、2つの別々のインスタンスは次のようにエンコードおよび直列化されます:

"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)。

トレーラは中継者によってヘッダーにマージされたり完全に削除される可能性があるため(Section 6.5.1 of [HTTP])、署名にトレーラを含めるのは署名者が検証者もトレーラ値にアクセスできることを知っている場合を除きNOT RECOMMENDEDです。

2.2. 導出コンポーネント

HTTP フィールドに加えて、制御データ、署名コンテキスト、または署名される HTTP メッセージのその他の側面から導出できるさまざまなコンポーネントがあります。そのような導出コンポーネントは、コンポーネント名、可能なパラメータ、メッセージターゲット、およびそのコンポーネント値の導出方法を定義することで署名ベースに含められます。

導出コンポーネント名は @ 文字で始まらなければならないことがMUSTです。これにより導出コンポーネント名は HTTP フィールド名(Section 5.1 に従い @ を含められない)と区別されます。HTTP メッセージ署名のプロセッサは導出コンポーネント名をフィールド名とは別に扱わなければなりません(Section 7.5.1 を参照)。

本仕様は次の導出コンポーネントを定義します:

@method
リクエストで使用されたメソッド(Section 2.2.1)。
@target-uri
リクエストの完全なターゲット URI(Section 2.2.2)。
@authority
リクエストのターゲット URI のオーソリティ(Section 2.2.3)。
@scheme
リクエストのターゲット URI のスキーム(Section 2.2.4)。
@request-target
リクエストターゲット(Section 2.2.5)。
@path
リクエストのターゲット URI の絶対パス部分(Section 2.2.6)。
@query
リクエストのターゲット URI のクエリ部分(Section 2.2.7)。
@query-param
リクエストのターゲット URI の解析およびエンコードされたクエリパラメータ(Section 2.2.8)。
@status
レスポンスのステータスコード(Section 2.2.9)。

追加の導出コンポーネント名は "HTTP Signature Derived Component Names" レジストリ(Section 6.4)で定義されます。

導出コンポーネント値は署名の対象メッセージのコンテキストから取られます。このコンテキストにはメッセージ自体に関する情報(制御データなど)や、署名者や検証者が保持する追加の状態やコンテキストが含まれます。特に、レスポンスに署名する際には、署名者は req パラメータを使用して元のリクエストから導出された任意の導出コンポーネントを含めることができます(Section 2.4)。

request:
HTTP リクエストメッセージから導出された値およびその結果。Section 3.4 of [HTTP] を参照。ターゲットメッセージがレスポンスである場合、Section 2.4 で定義された req パラメータを用いることでリクエストをターゲットとする導出コンポーネントを含められる。
response:
HTTP レスポンスメッセージから導出された値およびその結果(Section 3.4 を参照)。
request, response:
リクエストメッセージまたはレスポンスメッセージのいずれから導出された値。

導出コンポーネント定義は適用可能なすべてのターゲットメッセージ型を定義しなければなりません(MUST)。

導出コンポーネント値は印刷可能文字とスペースに限定され、改行文字を含んではならないことがMUSTです。導出コンポーネント値は先頭または末尾に空白文字を持ってはなりません(MUST NOT)。

2.2.1. メソッド

@method 導出コンポーネントはリクエストメッセージの HTTP メソッドを指します。コンポーネント値はメソッドの文字列値をそのまま取り正規化します。メソッド名は [HTTP] の規定に従って大文字小文字を区別することに注意してください(Section 9.1)。慣習的に標準化されたメソッド名は大文字ですが([ASCII])、入力メソッド値のケースを変換してはなりません。

例えば、次のようなリクエストメッセージ:

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

は次の @method コンポーネント値になります:

POST

および次の署名ベース行になります:

"@method": POST

2.2.2. ターゲット URI

@target-uri 導出コンポーネントはリクエストメッセージのターゲット URI を指します。コンポーネント値はリクエストのターゲット URI([HTTP]Section 7.1)であり、オーソリティを含む利用可能なすべての URI コンポーネントから組み立てられます。

例えば、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 導出コンポーネントは HTTP リクエストのターゲット URI のオーソリティ部分を指します([HTTP]Section 7.2)。HTTP/1.1 では通常 Host ヘッダーフィールドで伝えられ、HTTP/2 と HTTP/3 では :authority 擬似ヘッダで伝えられます。値はホストと(オプションで)ポートからなる完全修飾のオーソリティコンポーネントで文字列として表されます。コンポーネント値は [HTTP] の規則(Section 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推奨されます。詳細は Section 7.2.4 を参照してください。

2.2.4. スキーム

@scheme 導出コンポーネントはリクエストのターゲット URL のスキームを指します。コンポーネント値は [HTTP] の定義に従って小文字化された文字列として表されなければなりません(Section 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 リクエストメッセージの完全なリクエストターゲットを指します([HTTP]Section 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

絶対形式を用いる HTTP プロキシへの次のリクエスト(完全修飾ターゲット 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] によって定義されるリクエストターゲットの絶対パスであり、クエリ成分や末尾の疑問符(?)を含みません。値は [HTTP] の規則(Section 4.2.3)に従って正規化されます。空のパス文字列はスラッシュ(/)ひとつに正規化されます。パス成分はパーセントエンコードされたオクテットをデコードする前の値で表され、Section 6.2.1 の単純文字列比較規則に従います。

例えば、次のリクエストメッセージ:

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

は次の @path コンポーネント値になります:

/path

および次の署名ベース行になります:

"@path": /path

2.2.7. クエリ

@query 導出コンポーネントは HTTP リクエストのクエリ成分を指します。コンポーネント値は先頭の疑問符(?)を含む正規化されたクエリ文字列であり、[URI] によって定義されます。値は Section 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) のタプルのリストが得られます。各コンポーネント識別子の必須の name パラメータは単一のクエリパラメータのエンコード済みの nameString を String 値として含みます。単一の指定パラメータのコンポーネント値は、その単一のクエリパラメータのエンコード済み valueString です。複数の名前付きクエリパラメータをカバーに含めることはMAYです。単一の名前付きパラメータはクエリ文字列内の順序に関係なくカバーリスト内で任意の順序で出現してもよい(MAY)。

name パラメータの値および単一の名前付きパラメータのコンポーネント値は次の手順で計算されます:

  1. nameString または valueString[HTMLURL] の該当節に従ってパースする(パーセントエンコードされたオクテットをデコードした後の値)。

  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] の該当節で提供されるアルゴリズムは percent-escaped UTF-8 を用いるクエリパラメータのみをサポートします。その他のエンコーディングはサポートされません。さらに、同一名前のパラメータが複数回現れるケースはワイルドでは確実にサポートされていません。もしパラメータ名がリクエスト内で複数回出現する場合、その名前付きクエリパラメータは含めてはならない(MUST NOT)ことになっています。アプリケーション内で複数パラメータが一般的である場合は、Section 2.2.7 に定義された @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 ステータスコードを指します([HTTP]Section 15)。コンポーネント値は説明テキストを含まない 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 メッセージ署名には、カバーされたコンポーネントの順序付けられた集合や、署名作成のタイムスタンプ、検証鍵素材の識別子、およびその他のユーティリティを含む順序付けられたパラメータ集合など、署名の生成と検証に関するメタデータプロパティがあります。このメタデータは署名ベース内の特別なメッセージコンポーネントによって表され、他のメッセージコンポーネントとは若干異なる扱いを受けます。具体的には、署名パラメータのメッセージコンポーネントは署名ベースの最後の行として含めることがREQUIREDであり(Section 2.5)、このコンポーネント識別子自体を含めてどの署名でもカバーコンポーネントの集合内で列挙してはなりません(MUST NOT)。

署名パラメータのコンポーネント名は @signature-params です。

署名パラメータのコンポーネント値は、この署名のための署名パラメータの直列化であり、カバーされたコンポーネントの順序付けられた集合とすべての関連パラメータを含みます。これらのパラメータには次のものが含まれ得ます:

created:
作成時刻を UNIX タイムスタンプの Integer 型で示します。小数秒精度はサポートされません。このパラメータの包含はRECOMMENDEDです。
expires:
有効期限時刻を UNIX タイムスタンプの Integer 型で示します。小数秒精度はサポートされません。
nonce:
この署名のために生成されたランダムで一意な文字列値。
alg:
"HTTP Signature Algorithms" レジストリからの HTTP メッセージ署名アルゴリズムを String 値として示します。
keyid:
鍵素材の識別子を String 値として示します。
tag:
アプリケーション固有の署名タグを String 値として示します。これは特定のアプリケーションやプロトコルに関連する署名を識別するのに用いられます。

追加のパラメータは "HTTP Signature Metadata Parameters" レジストリ(Section 6.3)で定義できます。パラメータ群には一般的な順序はありませんが、一度特定のパラメータ集合に順序を選択するとその順序は署名パラメータ値を変更せずには変えられません。

署名パラメータコンポーネント値は Section 4 of [STRUCTURED-FIELDS] に従う parameterized Inner List として次のように直列化されます:

  1. 出力を空文字列とする。
  2. @signature-params コンポーネント識別子自体を除いた、カバーされたコンポーネントのコンポーネント識別子の順序を決定する。いったん選択された順序は変更できません。この順序は署名ベースの作成に使用した順序と同一でなければなりません(MUST)。
  3. カバーされたコンポーネントのコンポーネント識別子(すべてのパラメータを含む)を、String 値の順序付き Inner List として Section 4.1.1.1 の規則に従って直列化し、これを出力に追加する。コンポーネント識別子は自身のパラメータを含むことができ、これらのパラメータは順序付けられた集合である。あるコンポーネントのパラメータの順序が一度選択されると、その順序は変更できない。
  4. 署名パラメータの順序を決定する。一度選択された順序は変更できない。
  5. 利用可能な、またはこのメッセージ署名に使用されるパラメータを Section 4.1.1.2 の規則に従って Inner List に順序付けて追加する。
  6. 出力が署名パラメータコンポーネント値を含む。

ここで Section 4.1.1.1 の Inner List の直列化をカバーコンポーネント値に使用するのは、Section 4.1 で議論される Signature-Input フィールドへの並列性を促進するためです。

次の例は、例示的なメッセージ署名のパラメータに対する直列化されたコンポーネント値を示します:

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 メッセージは複数の署名を含み得ます(Section 4.3 を参照)が、単一の署名に使われる署名パラメータのみが各署名パラメータエントリに含まれる点に注意してください。

2.4. レスポンスメッセージ内でのリクエスト構成要素の署名

リクエストメッセージが署名されたレスポンスメッセージを生じさせる場合、署名者はコンポーネント識別子に req パラメータを追加することでリクエストメッセージの一部を署名ベースに含めることができます。

req
このコンポーネント値が署名対象のレスポンスメッセージではなく、このレスポンスを引き起こしたリクエストから導出されることを示すブールフラグ。

このパラメータは HTTP フィールドとリクエストをターゲットとする導出コンポーネントの両方に適用でき、同じ意味を持ちます。このパラメータを用いるメッセージコンポーネントのコンポーネント値は通常どおり計算されますが、データは署名が適用される対象のレスポンスメッセージの代わりにリクエストメッセージから引き出されます。

同じコンポーネント名は req パラメータの有無にかかわらず同一署名ベース内に含められてもよく(MAY)、それはリクエストメッセージとレスポンスメッセージの同名コンポーネントをそれぞれ示すことになります。

req パラメータはコンポーネント識別子に対して他のパラメータと組み合わせて用いることがMAYです(例えば Dictionary フィールドの key パラメータなど)。

例えば、次のリクエストに対するレスポンスを返す場合:

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"}

サーバーはレスポンスに対して自身の鍵で署名し、このアプリケーションにとって妥当な量のレスポンスをカバーするためにステータスコードやいくつかのヘッダーフィールドをカバーコンポーネントに含めます。加えて、サーバーはこのレスポンスを引き起こした元のリクエストメッセージから導出されたいくつかのコンポーネントをレスポンスのカバーコンポーネントに含めます。この例ではサーバーはリクエストのメソッド、オーソリティ、パス、および Content-Digest をレスポンス署名に含めています。リクエストとレスポンスの両方の Content-Digest がレスポンス署名に含まれています。この例のアプリケーションではクエリはレスポンスに関連がないと見なされ、カバーには含められていません。アプリケーションに応じて別の判断が行われるでしょう(Section 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 署名アルゴリズムは非決定論的であり、アルゴリズムを実行するたびに異なる署名値が生成されることに注意してください。提示された署名値は与えられた鍵に対して検証可能ですが、新たに生成された署名値が例と一致することは期待されません。詳細は Section 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 署名アルゴリズムは非決定論的であるため、アルゴリズムを実行するたびに異なる署名値が生成されます。提示された署名値は与えられた鍵で検証できますが、新しく生成された署名値が例と一致することは期待されません。詳細は Section 7.3.5 を参照してください。

署名済みリクエストに対してレスポンスを署名するアプリケーションは、署名がカバーするコンポーネントのすべてを署名することにより、衝突攻撃の一部に対する十分なカバレッジと保護を提供することがSHOULD推奨されます(Section 7.3.7 を参照)。この例のサーバーはクライアントのリクエスト署名の Signature-Input フィールドに列挙されたすべてのコンポーネントをレスポンス署名に含めています。

リクエストメッセージの Signature と Signature-Input フィールドをレスポンスの署名コンポーネントに含めることは構文的には可能ですが、この慣行はNOT RECOMMENDEDです。署名の署名は期待されるような覆い下の遷移的カバレッジを提供せず、Section 7.3.7 で議論されるいくつかの攻撃に対して脆弱だからです。署名の処理成功や受領を安全に示す必要があるアプリケーションは、そのような信号を安全に送るための代替メカニズムを慎重に指定する必要があります。

このフラグを用いる場合、レスポンス署名はリクエストメッセージに含まれるものだけをカバーできることに注意してください。したがって、アプリケーションがリクエストのメッセージ内容をレスポンスの署名に含める必要がある場合、クライアントは Content-Digest フィールドのようなコンテンツをカバーする手段を含める必要があります。詳細は Section 7.2.8 を参照してください。

req パラメータはリクエストをターゲットとする署名に対しては使用してはなりません(MUST NOT)。

2.5. 署名ベースの作成

署名ベースは、署名でカバーされる正規化された HTTP メッセージコンポーネントを含む ASCII 文字列 [ASCII] です。署名ベース作成アルゴリズムへの入力は、順序付けられたカバーされたコンポーネント識別子の集合とそれらに関連付けられた値、および Section 2.3 で述べる追加の署名パラメータです。

コンポーネント識別子は、[STRUCTURED-FIELDS]Section 4 で定義された厳密な直列化規則を用いて直列化されます。コンポーネント識別子はコンポーネント名を持ち、これは sf-string ABNF ルールで直列化された String Item 値です。コンポーネント識別子は定義されたパラメータを含むことがMAYあり、これらは parameters ABNF ルールで直列化されます。Section 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

署名ベースを作成するために、署名者または検証者は署名のカバーされたコンポーネントそれぞれのコンポーネント識別子(およびそのパラメータ)に対するエントリを次のアルゴリズムに従って連結します。ここで説明されるすべてのエラーは、署名ベースを出力することなくただちにアルゴリズムを失敗させることがMUSTです。

  1. 出力を空の文字列とする。
  2. カバーされたコンポーネント集合内の各メッセージコンポーネント項目について(順に):

    11.
    コンポーネント識別子(そのパラメータを含む)が既に署名ベースに追加されている場合、エラーを出す。
    12.
    該当するカバーコンポーネントのコンポーネント識別子を component-identifier ABNF ルールに従って直列化して追加する。注: この直列化はコンポーネント名を二重引用符で囲み、パラメータは引用符の外に追加する。
    13.
    単一のコロン(:)を追加する。
    14.
    単一の空白(" ")を追加する。
    15.

    コンポーネント識別子のためのコンポーネント値を決定する。

    • コンポーネント識別子に理解されないパラメータがある場合、エラーを出す。
    • bssf のように互いに矛盾するパラメータを含む場合、エラーを出す。
    • コンポーネント識別子に req パラメータが含まれ、かつターゲットメッセージがリクエストである場合、エラーを出す。
    • コンポーネント識別子に req パラメータが含まれ、かつターゲットメッセージがレスポンスである場合、コンポーネント値のコンテキストはそのレスポンスメッセージに関連するリクエストメッセージである。さもなければ、コンポーネント値のコンテキストはターゲットメッセージである。
    • コンポーネント名が "at" (@) で始まる場合、導出コンポーネントとして定義された特定の規則に従ってメッセージから値を導出する(Section 2.2 を参照)。既知の有効なパラメータがあればそれらを処理する。導出コンポーネント名が不明であるか、値が導出できない場合、エラーを出す。
    • コンポーネント名が "at" (@) で始まらない場合、Section 2.1 に記述されたとおり HTTP フィールド値を正規化し、既知の有効なパラメータを処理する。フィールドがメッセージ内で見つからない、またはコンテキスト内で値が取得できない場合、エラーを出す。
    16.
    カバーされたコンポーネントの正規化済みコンポーネント値を追加する。
    17.
    単一の改行(\n)を追加する。
  3. 次に、Section 2.3 に従って署名パラメータコンポーネントを signature-params-line ルールに従って追加する:

    11.
    署名パラメータのコンポーネント識別子を component-identifier ルールに従って直列化して追加する。すなわち正確な値 "@signature-params"(二重引用符を含む)を追加する。
    12.
    単一のコロン(:)を追加する。
    13.
    単一の空白(" ")を追加する。
    14.
    Section 2.3 で定義されたとおり、署名パラメータの正規化済みコンポーネント値(パラメータを持つ Inner List Structured Field 値)を追加する。
  4. 出力文字列に非 ASCII 文字が含まれている場合、エラーを出す [ASCII]
  5. 出力文字列を返す。

カバーされたコンポーネントがメッセージ内でコンポーネント値に解決できないコンポーネント識別子を参照している場合、実装はエラーを発生させ署名ベースを作成してはならないことがMUSTです。そのような状況には、以下が含まれますがこれらに限定されません:

  • 署名者または検証者が導出コンポーネント名を理解していない。
  • コンポーネント名がメッセージに存在しないフィールドを指している、またはその値が不正である。
  • コンポーネント識別子に不明なパラメータが含まれている、またはその識別子に適用できないパラメータが含まれている。
  • コンポーネント識別子が Structured Field の直列化を示す(sf パラメータ経由)にもかかわらず、そのフィールドが 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"}

カバーされたコンポーネントは、@method@authority、および @path の導出コンポーネントに続き、順に Content-DigestContent-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"

図 1: 非規範的な例の署名ベース

上の例の署名ベースには表示を終えるための最後の改行は含まれておらず、本仕様の他の例の署名ベースにも同様である点に注意してください。


3. HTTP メッセージ署名

HTTP メッセージ署名は、HTTP メッセージのコンポーネントのサブセットから生成された文字列に対する署名と、署名自体に関するメタデータの両方に対する署名です。HTTP メッセージに対して正常に検証された場合、HTTP メッセージ署名は、署名が作成されたメッセージと検証対象のメッセージが、署名されたメッセージコンポーネントのサブセットに関して意味的に同等であるという暗号学的証拠を提供します。

3.1. 署名の作成

HTTP メッセージ署名の作成は、署名コンテキスト(ターゲットメッセージを含む)とアプリケーションの要件を入力として取り、出力として署名値と署名パラメータの集合を生成し、それらをメッセージに追加して検証者に伝達できるようにするプロセスです。

署名を作成するために、署名者は次のアルゴリズムを適用することがMUSTです:

  1. 署名者は、利用可能な署名アルゴリズムの集合から HTTP 署名アルゴリズムと鍵素材を選択する。利用可能なアルゴリズムの集合はアプリケーションにより決定され、本書の対象外である。署名者はアルゴリズムに適した鍵素材を選び、鍵サイズや形式などアルゴリズムで定義される要件に従わなければならない(MUST)。鍵とアルゴリズムの選択機構は本書の範囲外である。
  2. 署名者は署名の作成時刻を現在時刻に設定する。
  3. 該当する場合、署名者は署名の有効期限プロパティを署名が失効する時刻に設定する。期限は検証者へのヒントであり、署名者がその時刻以降署名に対する保証を行わないことを表す。適切な有効期限の長さやこのパラメータの処理要件はアプリケーション固有である。
  4. 署名者は、署名でカバーするメッセージコンポーネントを表すコンポーネント識別子の順序付けられた集合を作成し、この集合に署名メタデータパラメータを付与する。この集合の直列化された値は、後に Section 4.1 で説明される Signature-Input フィールドの値として使用される。

    • 一度カバーコンポーネントの順序が決定されたら、その順序は署名の寿命の間変更してはならない(MUST NOT)。
    • 各カバーコンポーネント識別子は、署名コンテキスト内で(1)HTTP フィールド(Section 2.1)であるか、(2)Section 2.2 または "HTTP Signature Derived Component Names" レジストリに列挙された導出コンポーネントでなければならない(MUST)。
    • リクエストの署名者は、@method@authority@target-uri などのメッセージ制御データをカバーコンポーネントに含めることを SHOULD する。
    • 署名者は署名作成時刻を示すために created 署名メタデータパラメータを含めることを SHOULD する。
    • @signature-params 導出コンポーネント識別子はカバーコンポーネント識別子の一覧に存在してはならない(MUST NOT)。この導出コンポーネントは常に署名ベースの最後の行である必要があり、署名が常に自身のメタデータをカバーし、メタデータを置換できないことを保証する。
    • この集合に何を含め、どの順序にするかについての追加の指針は本書の範囲外である。
  5. 署名者はこれらのパラメータと署名ベース作成アルゴリズム(Section 2.5)を用いて署名ベースを作成する。
  6. 署名者は選択した署名アルゴリズムと選択した鍵素材を用いて HTTP_SIGN プリミティブ関数で署名ベースに署名する。HTTP_SIGN プリミティブおよび署名アルゴリズムの具体的な適用は Section 3.3 で定義される。
  7. 署名関数のバイト配列出力が、Section 4.2 で定義される Signature フィールドに含める HTTP メッセージ署名出力値となる。

例えば、Section 2.5 の例の HTTP メッセージと署名パラメータに対して、署名ベースは test-key-rsa-pss 鍵(Appendix B.1.2 を参照)と Section 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==

図 2: 非規範的な例の署名値

ここで使用されている RSA-PSS アルゴリズムは非決定論的であり、アルゴリズムを実行するたびに異なる署名値が生成されることに注意してください。提示された署名値は与えられた鍵に対して検証可能ですが、新たに生成された署名値が例と一致することは期待されません。詳細は Section 7.3.5 を参照してください。

3.2. 署名の検証

HTTP メッセージ署名の検証は、署名コンテキスト(ターゲットメッセージ、特にその Signature および Signature-Input フィールドを含む)とアプリケーションの要件を入力として取り、出力として正の検証結果またはエラーを返すプロセスです。

署名を検証するために、検証者は次のアルゴリズムを適用することがMUSTです:

  1. Signature および Signature-Input フィールドを Sections 4.1 および 4.2 に従って解析し、検証すべき署名とそのラベルを抽出する。

    11.
    複数の署名値が存在する場合、このメッセージに対してどの署名を処理すべきかを検証者のポリシーと構成に基づいて決定する。適用可能な署名が見つからない場合、エラーを出す。
    12.
    選択した Signature フィールド値に対応する Signature-Input フィールド値(同じラベルを持つもの)がない場合、エラーを出す。
  2. 選択した Signature-Input フィールドの値を parameterized Inner List として解析し、カバーされたコンポーネントの順序付けられたリストと署名パラメータを取得する。
  3. 対応する Signature フィールドの値を解析して、検証すべき署名のバイト配列値を取得する。
  4. 署名パラメータを調べ、本書およびアプリケーションが定義する追加要件(例えばどのメッセージコンポーネントが署名されるべきか)を満たしているか確認する(Section 3.2.1)。
  5. この署名に対する検証鍵素材を決定する。鍵素材が静的設定や外部プロトコル交渉などの外部手段で既知である場合、検証者はその外部知識から鍵素材を取得する手法を用いる。もし署名パラメータで鍵が識別されている場合、検証者は鍵識別子を参照して適切な鍵素材を取得する。検証者は、そのコンテキストで鍵素材が信頼に足るかどうか判断しなければならない。検証者が知らないか信頼できない鍵、またはこの要求に対して一致しない鍵が識別された場合、検証はMUST失敗する。
  6. 検証に適用するアルゴリズムを決定する:

    11.
    アプリケーションが既知とする許容アルゴリズムの集合から開始する。以下のいずれかの手順で選択されたアルゴリズムがこの集合に含まれない場合、署名検証は失敗する。
    12.
    アルゴリズムが静的設定や外部プロトコル交渉など外部手段で既知である場合、検証者はそのアルゴリズムを使用する。
    13.
    鍵素材からアルゴリズムが決定できる場合(例えば鍵値自体にアルゴリズムフィールドがある場合)、検証者はそのアルゴリズムを使用する。
    14.
    署名パラメータで "HTTP Signature Algorithms" レジストリの値を用いてアルゴリズムが明示されている場合、検証者は参照されたアルゴリズムを使用する。
    15.
    アルゴリズムが複数の場所で指定されている場合(例えば静的設定、署名パラメータの alg、鍵素材自身の組合せ)、解決されたアルゴリズムは同一でなければならない(MUST)。一致しない場合、検証者は検証を失敗させる(MUST)。
  7. 受信した HTTP メッセージと解析した署名パラメータを用いて、Section 2.5 に定義されたアルゴリズムを使用して署名ベースを再作成する。@signature-params の入力値は、この署名のための Signature-Input フィールドの値を Section 2.3 に記述された規則に従って直列化したものになることに注意する。なお、これは Signature-Input フィールドのラベルを含まない。
  8. 鍵素材がアルゴリズムに適切であれば、再計算した署名ベース、鍵素材、および署名値に対して適切な HTTP_VERIFY 暗号検証アルゴリズムを適用する。HTTP_VERIFY プリミティブおよびいくつかの具体的アルゴリズムは Section 3.3 に定義される。
  9. 検証アルゴリズム関数の結果が暗号検証の最終結果となる。

上記のいずれかのステップが失敗またはエラーを出した場合、署名検証は失敗する。

例えば、次のメッセージのラベル sig1 の署名を test-key-rsa-pss 鍵(Appendix B.1.2)と RSASSA-PSS アルゴリズム(Section 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 タイムスタンプの有効期限を過ぎた署名を拒否する。expires は署名者からのヒントであり、検証者は常に有効期限前に署名を拒否できることに注意する。
  • 署名メタデータパラメータの中で、例えば鍵情報からアルゴリズムが決定される場合の alg によるランタイムアルゴリズムシグナリングを禁止する。
  • keyid パラメータのデリファレンスが有効で適切な鍵素材に成功することを保証する。
  • 特定のアルゴリズムの使用を禁止する、または特定のアルゴリズムの使用を義務付ける。
  • 鍵のサイズを要件とする(例: 2048 ビット vs 1024 ビット)。
  • nonce パラメータの一意性を強制する。
  • tag パラメータにアプリケーション固有の値を要求する。

アプリケーション固有の要件は期待され推奨されます。アプリケーションが追加要件を定義する場合、それらを署名検証プロセス中に強制し、署名がアプリケーション要件に適合しない場合は署名検証を失敗させることがMUSTです。

アプリケーションは本書で定義された要件を強制することがMUSTです。ユースケースにかかわらず、これらの要件に適合しない署名を受け入れてはなりません(MUST NOT)。

3.3. 署名アルゴリズム

HTTP メッセージ署名は、鍵素材、環境、および署名者と検証者のニーズに適した暗号デジタル署名または MAC 方法を使用しなければなりません(MUST)。本仕様は利用可能な署名アルゴリズムを厳密に制限するものではなく、これらの基本要件を満たす任意の署名アルゴリズムは HTTP メッセージ署名のアプリケーションで使用できる(MAY)ことに注意してください。

各署名方式について、HTTP_SIGN は署名ベース(Section 2.5)をバイト配列として(M)と署名鍵素材(Ks)を入力とし、出力として署名のバイト配列(S)を生成します:

HTTP_SIGN (M, Ks)  ->  S

各検証方式について、HTTP_VERIFY は再生成された署名ベース(バイト配列、M)、検証鍵素材(Kv)、および検証対象の提示された署名(バイト配列、S)を入力とし、検証結果(ブール値、V)を出力します:

HTTP_VERIFY (M, Kv, S) -> V

以下の節では、いくつかの一般的な署名アルゴリズムを示し、これらの暗号プリミティブが上記の HTTP_SIGN および HTTP_VERIFY 定義にどのように対応するかを説明します。使用する方法は、明示的なアルゴリズム(alg)署名パラメータ(Section 2.3)で伝えるか、鍵素材への参照、または署名者と検証者の間の合意によって決定できます。alg パラメータで選択された署名アルゴリズムは、"HTTP Signature Algorithms" レジストリ(Section 6.2)の値を使用しなければなりません(MUST)。

3.3.1. RSASSA-PSS(SHA-512 使用)

このアルゴリズムで署名するには、署名者は署名者の秘密鍵(K)と署名ベース(M)を用いて、[RFC8017] で定義された RSASSA-PSS-SIGN (K, M) 関数を適用します(Section 2.5)。マスク生成関数は MGF1 でハッシュ関数は SHA-512([RFC6234])です。ソルト長(sLen)は 64 バイトです。ハッシュ関数 SHA-512 は署名ベースに適用され、デジストコンテンツが作成され、それにデジタル署名が適用されます。得られた署名済みバイト配列(S)が HTTP メッセージ署名出力です(Section 3.1 参照)。

このアルゴリズムで検証するには、検証者は検証鍵素材の公開鍵部分(n, e)と再作成した署名ベース(M)を用いて、[RFC8017]RSASSA-PSS-VERIFY ((n, e), M, S) 関数を適用します。マスク生成関数は MGF1、ハッシュ関数は SHA-512、ソルト長は 64 バイトです。ハッシュ関数 SHA-512 は署名ベースに適用され、検証関数に与えられるダイジェストが作成されます。検証者は検証すべき HTTP メッセージ署名(S)を Section 3.2 に従って抽出します。検証関数の結果は提示された署名が有効か否かを示します。

RSASSA-PSS の出力は非決定論的であるため、署名ベースに対して新たに署名を計算し既存の署名と比較するのは正しくありません。代わりにここで定義された検証アルゴリズムを使用する必要があります。詳しくは Section 7.3.5 を参照してください。

このアルゴリズムの使用は、署名パラメータ algrsa-pss-sha512 を指定することでランタイムに示すことができます。

3.3.2. RSASSA-PKCS1-v1_5(SHA-256 使用)

このアルゴリズムで署名するには、署名者は秘密鍵(K)と署名ベース(M)を用いて、[RFC8017] で定義された RSASSA-PKCS1-V1_5-SIGN (K, M) 関数を適用します(Section 2.5)。ハッシュ関数 SHA-256([RFC6234])が署名ベースに適用され、デジストコンテンツに対してデジタル署名が行われます。得られた署名バイト配列(S)が HTTP メッセージ署名出力として使用されます(Section 3.1)。

このアルゴリズムで検証するには、検証者は公開鍵部分(n, e)と再作成した署名ベース(M)を用いて、[RFC8017]RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S) 関数を適用します。ハッシュ関数は SHA-256 です。検証者は検証すべき署名(S)を Section 3.2 に従って抽出し、検証関数の結果が署名が有効かどうかを示します。

このアルゴリズムの使用は、署名パラメータ algrsa-v1_5-sha256 を指定することで示すことができます。

3.3.3. HMAC Using SHA-256

このアルゴリズムで署名および検証を行うには、署名者は共有署名鍵(K)と署名ベース(text)(Section 2.5)を用いて HMAC 関数([RFC2104])を適用します。ハッシュ関数 SHA-256([RFC6234])が署名ベースに対して適用され、そのダイジェストに対して HMAC が計算され、署名結果が得られます。

署名の際、得られた値は Section 3.1 で使用される HTTP メッセージ署名出力になります。

検証の際、検証者は検証対象の HTTP メッセージ署名(S)を Section 3.2 に従って抽出します。HMAC 関数の出力はバイト単位で提示された HTTP メッセージ署名の値と比較され、その比較結果によって提示された署名の妥当性が判断されます。

このアルゴリズムの使用は、署名パラメータ alghmac-sha256 の値を指定することでランタイムに示すことができます。

3.3.4. ECDSA Using Curve P-256 DSS and SHA-256

このアルゴリズムで署名するには、署名者は曲線 P-256 を用いた ECDSA 署名アルゴリズム([FIPS186-5])を、署名者の秘密署名鍵と署名ベース(Section 2.5)に対して適用します。ハッシュ SHA-256([RFC6234])が署名ベースに適用され、そのダイジェストにデジタル署名が適用されます(M)。署名アルゴリズムは 2 つの整数値、すなわち rs を返します。これらはどちらもビッグエンディアンの符号なし整数としてエンコードされ、それぞれ 32 オクテットにゼロパディングされます。エンコードされた値は順に連結され、r のエンコード値に続いて s のエンコード値が続く単一の 64 オクテット配列になります。得られた (r, s) の連結は、Section 3.1 で使用される HTTP メッセージ署名出力のバイト配列です。

このアルゴリズムで検証するには、検証者は検証鍵素材の公開鍵部分と、Section 3.2 に従って再生成した署名ベースを用いて ECDSA 署名アルゴリズム([FIPS186-5])を適用します。ハッシュ関数 SHA-256([RFC6234])が署名ベースに適用され、そのダイジェストに対して検証関数が適用されます(M)。検証者は検証対象の HTTP メッセージ署名(S)を Section 3.2 に従って抽出します。この値は rs のエンコード値が順に連結された 64 オクテット配列です。これらはどちらもビッグエンディアンの符号なし整数として 32 オクテットにゼロパディングされています。得られた署名値 (r, s) が検証関数への入力として使用され、検証関数の結果が提示された署名の有効性を示します。

ECDSA 署名アルゴリズムの出力は非決定論的であるため、署名ベースに対して新たに署名を計算し既存の署名と比較することは正しくありません。代わりにここで定義された検証アルゴリズムを使用する必要があります。詳細は Section 7.3.5 を参照してください。

このアルゴリズムの使用は、署名パラメータ algecdsa-p256-sha256 の値を指定することでランタイムに示すことができます。

3.3.5. ECDSA Using Curve P-384 DSS and SHA-384

このアルゴリズムで署名するには、署名者は曲線 P-384 を用いた ECDSA 署名アルゴリズム([FIPS186-5])を、署名者の秘密署名鍵と署名ベース(Section 2.5)に対して適用します。ハッシュ SHA-384([RFC6234])が署名ベースに適用され、そのダイジェストにデジタル署名が適用されます(M)。署名アルゴリズムは 2 つの整数値、すなわち rs を返します。これらはどちらもビッグエンディアンの符号なし整数としてエンコードされ、それぞれ 48 オクテットにゼロパディングされます。エンコードされた値は順に連結され、r のエンコード値に続いて s のエンコード値が続く単一の 96 オクテット配列になります。得られた (r, s) の連結は、Section 3.1 で使用される HTTP メッセージ署名出力のバイト配列です。

このアルゴリズムで検証するには、検証者は検証鍵素材の公開鍵部分と再生成した署名ベース(Section 3.2 に従って)を用いて ECDSA 署名アルゴリズム([FIPS186-5])を適用します。ハッシュ関数 SHA-384([RFC6234])が署名ベースに適用され、そのダイジェストに対して検証関数が適用されます(M)。検証者は検証対象の HTTP メッセージ署名(S)を Section 3.2 に従って抽出します。この値は rs のエンコード値が順に連結された 96 オクテット配列です。これらはどちらもビッグエンディアンの符号なし整数として 48 オクテットにゼロパディングされています。得られた署名値 (r, s) が検証関数への入力として使用され、検証関数の結果が提示された署名の有効性を示します。

ECDSA 署名アルゴリズムの出力は非決定論的であるため、署名ベースに対して新たに署名を計算し既存の署名と比較することは正しくありません。代わりにここで定義された検証アルゴリズムを使用する必要があります。詳細は Section 7.3.5 を参照してください。

このアルゴリズムの使用は、署名パラメータ algecdsa-p384-sha384 の値を指定することでランタイムに示すことができます。

3.3.6. EdDSA Using Curve edwards25519

このアルゴリズムで署名するには、署名者は署名者の秘密署名鍵と署名ベース(Section 2.5)を用いて Ed25519 アルゴリズム([RFC8032] の該当節)を適用します。署名ベースはプレハッシュ関数を用いずそのまま入力メッセージ(M)として扱われます。署名は RS の 64 オクテット連結であり([RFC8032] の規定に従う)、これが Section 3.1 で使用される HTTP メッセージ署名出力のバイト配列になります。

このアルゴリズムで検証するには、検証者は検証鍵素材の公開鍵部分(A)と、Section 3.2 に従って再生成した署名ベースを用いて Ed25519 検証アルゴリズム([RFC8032] の該当節)を適用します。署名ベースはプレハッシュ関数を用いずそのまま入力メッセージ(M)として扱われます。検証対象の署名は RS の 64 オクテット連結として扱われ、検証関数の結果が提示された署名の有効性を示します。

このアルゴリズムの使用は、署名パラメータ alged25519 の値を指定することでランタイムに示すことができます。

3.3.7. JSON Web Signature (JWS) Algorithms

署名アルゴリズムが JOSE の署名アルゴリズム("JSON Web Signature and Encryption Algorithms" レジストリにあるもの)である場合、JWS のアルゴリズム定義が署名とハッシュの方法を決定します([RFC7518])。

署名と検証の両方で、HTTP メッセージの署名ベース(Section 2.5)がそのまま「JWS Signing Input」として使用されます。JOSE ヘッダ([JWS][RFC7517])は使用されず、署名ベースは JOSE のようにまず Base64url エンコードされてからアルゴリズムを適用することはありません。JWS 署名の出力は、JOSE で使用される Base64url エンコード前のバイト配列として扱われます。

JWS アルゴリズムは "none" であってはならず(MUST NOT)、また JOSE 実装要件が "Prohibited" とされるアルゴリズムであってはなりません(MUST NOT)。

"JSON Web Algorithm (JWA)" の値は "HTTP Signature Algorithms" レジストリには含まれません。通常、JWS のアルゴリズムは JWK など JOSE 実装で一般的な仕組みによって伝達されます。実際、JWA 値は "HTTP Signature Algorithms" レジストリに登録されていないため、JOSE の署名アルゴリズムを使用する場合は明示的な署名パラメータ alg は用いられません。


4. Including a Message Signature in a Message

HTTP メッセージ署名は、本仕様で定義された Signature-Input および Signature フィールドを通じて HTTP メッセージ内に含めることができます。

Signature-Input フィールドは署名がどのように生成されたかを記述するカバーされたコンポーネントとパラメータを識別し、Signature フィールドは署名値を含みます。各フィールドは複数のラベル付き値を含めることがMAYあります。

HTTP メッセージ署名は HTTP メッセージ内のラベルによって識別されます。このラベルは特定の HTTP メッセージ内で一意でなければならず(MUST)、Signature-Input フィールドと Signature フィールドの両方で使用されなければなりません。ラベルは通常署名者が選択しますが、Section 5 のようなプロトコル交渉で特定のラベルが指示される場合もあります。

HTTP メッセージ署名は Signature-Input フィールドと Signature フィールドの両方を使用しなければならず(MUST)、各フィールドは同じラベルを含む必要があります。一方のフィールドにラベルが存在して他方に存在しないことはエラーです。

4.1. The Signature-Input HTTP Field

Signature-Input フィールドは Dictionary Structured Field(Section 3.2 of [STRUCTURED-FIELDS])であり、HTTP メッセージ内のコンポーネントから生成された 1 つ以上のメッセージ署名のメタデータを含みます。各メンバーは単一のメッセージ署名を記述します。メンバーのキーは HTTP メッセージ内でメッセージ署名を一意に識別するラベルです。メンバーの値は Inner List として直列化されたカバーされたコンポーネントの順序付けられた集合であり、ラベルで識別されるすべての署名メタデータパラメータを含みます:

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です(Section 2.3 を参照)。Structured Field 値ではリストの順序およびパラメータの順序が保持される必要があることに注意してください。

署名者は署名処理が完了した後にメッセージのコンテンツを署名するために Signature-Input フィールドをトレーラとして含めることがMAYです。しかし中継者はトレーラを削除することが許されるため([HTTP])、署名がメッセージから意図せず取り除かれるのを避けるために、Signature-Input フィールドはヘッダーフィールドとしてのみ含めることがRECOMMENDEDされます。

単一の HTTP メッセージに複数の Signature-Input フィールドを含めることがMAYです。署名ラベルはすべてのフィールド値にわたって一意でなければなりません(MUST)。

4.2. The Signature HTTP Field

Signature フィールドは Dictionary Structured Field(Section 3.2 of [STRUCTURED-FIELDS])であり、ターゲットメッセージの署名コンテキストから生成された 1 つ以上のメッセージ署名を含みます。メンバーのキーは 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. Multiple Signatures

複数の異なる署名を単一のメッセージに含めることが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 フィールドを新しい署名のカバーコンポーネントに含めることは可能ですが、署名値を署名することには既知の弱点があるためこれはNOT RECOMMENDEDです(詳しくは Section 7.3.7 を参照)。プロキシはクライアントの署名を検証できる立場にあり、プロキシが行うメッセージ変更はオリジンサーバーが見ると既存の署名を無効にします。この例では、オリジンサーバーが権限の変更を考慮するための追加情報を署名コンテキストに持っている可能性がありますが、この慣行には追加の設定と注意が必要です(Section 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(Section 3.2 of [STRUCTURED-FIELDS])であり、ターゲット HTTP メッセージのメッセージコンポーネントから生成される 1 つ以上の要求されたメッセージ署名のメタデータを含みます。各メンバーは単一のメッセージ署名を記述します。メンバーのキーは、ターゲット HTTP メッセージのコンテキスト内で要求されたメッセージ署名を一意に識別するラベルです。

メンバーの値は、Section 2.3 に定義された直列化プロセスを使用して、ターゲットメッセージの所望のカバーされたコンポーネント(および許可されるコンポーネントメタデータパラメータ)を直列化したものです:

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:
署名者に作成時刻を生成して含めることを要求します。このパラメータは署名要求として送信されるときは値を伴いません。
expires:
署名者に有効期限時刻を生成して含めることを要求します。このパラメータは署名要求として送信されるときは値を伴いません。
nonce:
署名者に、このパラメータの値をターゲット署名の nonce として含めることを要求します。
alg:
署名者に "HTTP Signature Algorithms" レジストリから示された署名アルゴリズムを使用してターゲット署名を作成することを要求します。
keyid:
署名者に示された鍵素材を使用してターゲット署名を作成することを要求します。
tag:
署名者にこのパラメータの値をターゲット署名の tag として含めることを要求します。

5.2. Accept-Signature の処理

Accept-Signature フィールドの受信者は、次の手順でそのヘッダーを履行します:

  1. フィールド値を Dictionary として解析する。
  2. Dictionary の各メンバーについて:

    11.
    キーは Section 4.1 に指定されているように、出力署名のラベルとして扱われます。
    12.
    メンバーの値を解析して、カバーされたコンポーネント識別子の集合を取得する。
    13.
    カバーされたコンポーネントがターゲットメッセージに適用可能であることを判定する。適用できない場合、処理は失敗しエラーを返す。
    14.
    要求されたパラメータ(署名アルゴリズムや鍵素材など)を処理する。要求されたパラメータが満たせないか、ターゲットメッセージに適切であると見なされるものと矛盾する場合、処理は失敗しエラーを返す。
    15.
    署名を完了するために必要な追加のパラメータを選択および生成する。
    16.
    ターゲットメッセージに対して HTTP メッセージ署名を作成する。
    17.
    Signature-Input および Signature フィールド値を作成し、それらをラベルに関連付ける。
  3. 必要に応じて、Accept-Signature フィールドに見つからない一意のラベルを持つ追加の Signature-Input および Signature フィールド値を作成することができる。
  4. すべてのラベル付き Signature-Input および Signature フィールド値を結合し、両方のフィールドをターゲットメッセージに付加する。

このプロセスにより、ターゲットメッセージに適用された署名は同一のラベルを持ち、同一のカバーコンポーネント集合を含み、要求されたすべてのパラメータを処理し、追加のパラメータを持つことがMAYあり得ます(ただし必須ではありません)。

Accept-Signature フィールドの受信者は、アプリケーションのパラメータに合致しない署名要求を無視してもよいことがMAYです。

ターゲットメッセージは、Accept-Signature フィールドで指定されていない追加の署名を含めることがMAYです。例えば、追加のメッセージコンポーネントをカバーするために、署名者は要求された署名の出力を含む追加コンポーネントを含む二番目の署名を作成することができます。


6. IANA に関する考慮事項

IANA は 1 つのレジストリを更新し、4 つの新しいレジストリを作成しました。詳細は以下の節に従います。

6.1. HTTP フィールド名登録

IANA は "Hypertext Transfer Protocol (HTTP) Field Name Registry" のエントリを次のように更新しました:

Table 1: Updates to the Hypertext Transfer Protocol (HTTP) Field Name Registry
Field Name Status Reference
Signature-Input permanent Section 4.1 of RFC 9421
Signature permanent Section 4.2 of RFC 9421
Accept-Signature permanent Section 5.1 of RFC 9421

6.2. HTTP Signature Algorithms Registry

本書は HTTP 署名アルゴリズムを定義しており、IANA は "HTTP Signature Algorithms" という新しいレジストリを作成し管理します。初期値は Section 6.2.2 に示されています。将来の割り当てや既存割り当ての変更は Specification Required 登録ポリシー ([RFC8126]) を通じて行われます。

このレジストリに記載されたアルゴリズムは、この仕様のアプリケーションで使用可能な暗号アルゴリズムの一部を識別しますが、可能なアルゴリズムの網羅的リストを示すものでも、特定の用途に対する適合性を示すものでもありません。アプリケーションは、署名者と検証者が安全かつ決定論的にアルゴリズムのパラメータに合意できる限り、自分たちのニーズに合う任意のアルゴリズムを実装できます。アプリケーションがランタイムで特定のアルゴリズムを alg 署名パラメータで指示する必要がある場合、このレジストリはそのパラメータ値と特定のアルゴリズムとの対応を提供します。ただし、アルゴリズムの混同や置換攻撃を避けるために alg パラメータの使用には注意が必要です(Section 7 を参照)。

Status 値は標準化状況および IETF やセキュリティ関連の標準化団体(SDO)などの関連利害関係者の広い意見を反映すべきです。アルゴリズムが初めて登録される際、Designated Expert (DE) はアルゴリズムが一般的に安全であるとのコンセンサスがある場合に Status フィールドを "Active" に設定し、コンセンサスが得られていない実験的アルゴリズムなどの場合は "Provisional" に設定すべきです。将来登録されたアルゴリズムに欠陥が見つかった場合、レジストリ項目は更新され "Deprecated" とされることがあります。DE は登録に対する Status 値の説明と参照を含めることができ、特に非推奨となったアルゴリズムに対して重要です。

DE は次のことを実行することが期待されます:

  • 登録されたアルゴリズムが参照するアルゴリズムについて、すべてのパラメータ(例: ソルト、ハッシュ、必要な鍵長)が定義文書で固定されていることを確認する。
  • アルゴリズム定義が HTTP_SIGN および HTTP_VERIFY プリミティブ関数を完全に特定し、すべての入力と出力が基礎となる暗号アルゴリズムにどのようにマッピングされるかを明確にすることを確認する。
  • 既存の登録のエイリアスである登録は拒否する。
  • すべての登録が Section 6.2.1 に示されたテンプレートに従うことを確認する。これには名前の長さが過度でないことを確認しつつ、固有で認識可能であることを含む。

本仕様は、アルゴリズム名に主要なパラメータを含めることで開発者にとって識別しやすくする識別子を作成します。しかし、このレジストリ内のアルゴリズム識別子は文字列全体として解釈され、部分ごとに分解してパラメータを決定するものではありません。例えば rsa-pss-sha512 を、ハッシュやマスク、ソルト値が定義文書で定められた特定のアルゴリズムを指すものとして理解することが期待されています。

6.2.1. 登録テンプレート

Algorithm Name:
HTTP 署名アルゴリズムの識別子。名前は MUST ASCII 文字列であり、sf-string ABNF ルールに準拠し(Section 3.3.3)、長さは 20 文字を超えないことがSHOULD NOT望ましい。識別子はレジストリ内で一意でなければなりません。
Description:
署名ベースに署名するために使用されるアルゴリズムの簡潔な説明。
Status:
アルゴリズムのステータス。MUST 以下の値のいずれかで始まり、追加の説明を含めることができます。選択肢は "Active", "Provisional", "Deprecated" です。
Reference:
アルゴリズムを特定する文書への参照(可能であれば URI を含む)。関連する節の指示も含め得ますが必須ではありません。

6.2.2. 初期内容

下表は "HTTP Signature Algorithms" レジストリの初期内容を示します。

Table 2: Initial Contents of the HTTP Signature Algorithms Registry
Algorithm Name Description Status Reference
rsa-pss-sha512 RSASSA-PSS using SHA-512 Active Section 3.3.1 of RFC 9421
rsa-v1_5-sha256 RSASSA-PKCS1-v1_5 using SHA-256 Active Section 3.3.2 of RFC 9421
hmac-sha256 HMAC using SHA-256 Active Section 3.3.3 of RFC 9421
ecdsa-p256-sha256 ECDSA using curve P-256 DSS and SHA-256 Active Section 3.3.4 of RFC 9421
ecdsa-p384-sha384 ECDSA using curve P-384 DSS and SHA-384 Active Section 3.3.5 of RFC 9421
ed25519 EdDSA using curve edwards25519 Active Section 3.3.6 of RFC 9421

6.3. HTTP Signature Metadata Parameters Registry

本書は署名パラメータ構造(Section 2.3)を定義します。IANA は "HTTP Signature Metadata Parameters" という新しいレジストリを作成し、署名パラメータ構造のメンバー値で使用されるパラメータを記録・管理します。初期値は Section 6.3.2 に示されています。将来の割り当てや変更は Expert Review 登録ポリシー ([RFC8126]) を通じて行われます。

DE は次のことを行うことが期待されます:

  • 名前が Section 6.3.1 に示されたテンプレートに従うことを確認する(長さが過度でないこと、一意かつ認識可能であることを含む)。
  • 定義された機能が明確であり他の登録済みパラメータと矛盾しないことを確認する。
  • メタデータパラメータの定義が、通常の署名プロセスで使用される場合と Accept-Signature フィールドで使用される場合の両方における振る舞いを含むことを確認する。

6.3.1. 登録テンプレート

Name:
HTTP 署名メタデータパラメータの識別子。名前は MUST ASCII 文字列であり、key ABNF ルールに準拠し(Section 3.1.2)、長さは 20 文字を超えないことがSHOULD NOT望ましい。識別子はレジストリ内で一意でなければなりません。
Description:
メタデータパラメータが何を表すかの簡潔な説明。
Reference:
パラメータを特定する文書への参照(可能であれば URI を含む)。関連節の指示も含め得ますが必須ではありません。

6.3.2. 初期内容

下表は "HTTP Signature Metadata Parameters" レジストリの初期内容を提示します。各行はレジストリ内の個別のエントリを表します。

Table 3: Initial Contents of the HTTP Signature Metadata Parameters Registry
Name Description Reference
alg 明示的に宣言された署名アルゴリズム Section 2.3 of RFC 9421
created 署名作成のタイムスタンプ Section 2.3 of RFC 9421
expires 提案された署名の有効期限タイムスタンプ Section 2.3 of RFC 9421
keyid この署名を作成するために使用される署名および検証鍵の鍵識別子 Section 2.3 of RFC 9421
nonce 使い捨ての nonce 値 Section 2.3 of RFC 9421
tag 署名のアプリケーション固有タグ Section 2.3 of RFC 9421

6.4. HTTP Signature Derived Component Names Registry

本書は HTTP メッセージコンポーネントを正規化する方法を定義しており、HTTP フィールド外のコンテキストから導出できるコンポーネントも含みます。これらの導出コンポーネントはコンポーネント名という一意の文字列で識別されます。導出コンポーネント名は常に "at"(@)記号で始まり、HTTP フィールド名と区別されます。IANA は "HTTP Signature Derived Component Names" という新しいレジストリを作成し、非フィールドのコンポーネント名とそれらに関連するコンポーネント値を生成する方法を記録・管理します。初期値は Section 6.4.2 に示されています。将来の割り当てや変更は Expert Review 登録ポリシー ([RFC8126]) を通じて行われます。

DE は次のことを行うことが期待されます:

  • Section 6.4.1 に示されたテンプレートに従うことを確認する(長さが過度でないこと、一意かつ認識可能であることを含む)。
  • 登録要求が示すコンポーネント値がターゲット HTTP メッセージから決定論的に導出可能であることを確認する。
  • 登録要求のために定義されたパラメータがそれらのコンポーネント値に与える影響を明確に文書化することを確認する。

DE は、登録が既存の導出コンポーネント定義と十分に区別されていることを確認すべきです。

登録項目のステータスを "Deprecated" に設定する際、DE は非推奨の理由と非推奨機能から移行するための指示を文書化するべきです。

6.4.1. 登録テンプレート

Name:
HTTP 導出コンポーネントの名前。名前は MUST "at" (@) 文字で始まり、その後に小文字の ASCII 文字("a"-"z")、数字("0"-"9")、およびハイフン("-")のみを含む ASCII 文字列でなければなりません。長さは 20 文字を超えないことがSHOULD NOT望ましい。名前はレジストリ内で一意でなければなりません。
Description:
導出コンポーネントの説明。
Status:
アルゴリズムのステータスに関する簡潔な説明。説明は "Active" または "Deprecated" のいずれかで始まらなければならず、必要に応じて理由を追加できます。"Deprecated" は導出コンポーネント名がもはや推奨されないことを示します。
Target:
導出パラメータの有効なメッセージターゲット。"Request"、"Response"、または "Request, Response" のいずれかでなければなりません。これらの意味は Section 2.2 に定義されています。
Reference:
導出コンポーネントを特定する文書への参照(可能であれば URI を含む)。関連節の指示も含め得ますが必須ではありません。

6.4.2. 初期内容

下表は "HTTP Signature Derived Component Names" レジストリの初期内容を示します。

Table 4: Initial Contents of the HTTP Signature Derived Component Names Registry
Name Description Status Target Reference
@signature-params 署名ベース内の署名パラメータ行のために予約 Active Request, Response Section 2.3 of RFC 9421
@method HTTP リクエストのメソッド Active Request Section 2.2.1 of RFC 9421
@authority HTTP のオーソリティ(ターゲットホスト) Active Request Section 2.2.3 of RFC 9421
@scheme リクエスト URI のスキーム Active Request Section 2.2.4 of RFC 9421
@target-uri リクエストの完全なターゲット URI Active Request Section 2.2.2 of RFC 9421
@request-target リクエストのリクエストターゲット Active Request Section 2.2.5 of RFC 9421
@path リクエスト URI の完全なパス Active Request Section 2.2.6 of RFC 9421
@query リクエスト URI の完全なクエリ Active Request Section 2.2.7 of RFC 9421
@query-param 単一の名前付きクエリパラメータ Active Request Section 2.2.8 of RFC 9421
@status レスポンスのステータスコード Active Response Section 2.2.9 of RFC 9421

6.5. HTTP Signature Component Parameters Registry

本書は複数の種類のコンポーネント識別子を定義しており、そのうちいくつかは特定の状況でパラメータ化され、固有の修正された振る舞いを提供することができます。IANA は "HTTP Signature Component Parameters" という新しいレジストリを作成し、現在これを維持しており、パラメータ名、それらが関連付けられるコンポーネント識別子、およびこれらのパラメータがコンポーネント値に対して行う変更を記録・管理します。パラメータの定義は、適用対象(特定のフィールド型、導出コンポーネント、またはコンテキストなど)を定義しなければなりません(MUST)。このレジストリの初期値は Section 6.5.2 に示されています。将来の割り当ておよび既存の割り当ての修正は Expert Review 登録ポリシーに従って行われます([RFC8126])。

Designated Expert (DE) は次のことを行うことが期待されます:

  • 名前が Section 6.5.1 に示されたテンプレートに従っていることを確認する。これは、名前の長さが過度にならない一方で、その定義された機能に対して一意で認識可能であることを確保することを含みます。
  • 登録要求時に既知の他のパラメータとの相互作用や非互換性を定義が十分に規定していることを確認する。
  • パラメータがコンポーネント値を変更する場合、そのパラメータを適用したコンポーネント識別子によって定義されるコンポーネント値が、ターゲットの HTTP メッセージから決定論的に導出可能であることを確認する。

6.5.1. Registration Template

Name:
パラメータの名前。名前は MUST Section 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 メッセージが署名によって「カバーされている」とみなされるためには、次のすべての条件が満たされている必要があります:

  • 検証者によってそのメッセージに署名が期待または許可されていること。
  • メッセージに署名が存在すること。
  • 署名が識別された鍵素材とアルゴリズムに対して検証されていること。
  • 鍵素材とアルゴリズムがそのメッセージのコンテキストに適切であること。
  • 署名が期待される時間範囲内にあること。
  • 署名が期待されるコンテンツ(重要なコンポーネントを含む)をカバーしていること。
  • カバーされたコンポーネントの一覧がメッセージのコンテキストに適用可能であること。

Section 1.4 に記載されたアプリケーション要件定義に加えて、以下のセキュリティ考慮事項は、HTTP メッセージに対する署名の作成と検証の要件に関して議論と文脈を提供します。

7.1. 一般的な考慮事項

7.1.1. 署名検証のスキップ

HTTP メッセージ署名は、検証者が署名を検証する場合にのみセキュリティを提供します。署名や Signature-Input フィールドがなくても署名が添付されたメッセージは有効な HTTP メッセージのままであるため、検証者が検証関数の出力を無視してメッセージを処理することが可能です。これには、開発環境での要件の緩和や、システム全体のデバッグ中に検証の強制を一時停止することなど、一般的な理由が考えられます。この種の一時的な停止は、良い署名であれば検査されなくても常に有効な応答を引き起こすため、ポジティブな例によるテストでは検出が難しいことがあります。

これを検出するために、検証者は有効な署名と無効な署名の両方を用いたテストを行い、無効な署名が期待どおり失敗することを確認すべきです。

7.1.2. TLS の使用

HTTP メッセージ署名の使用は、通信路上の情報を保護するために TLS や同等のものが不要になることを意味しません。メッセージ署名はカバーされたメッセージコンポーネントに対する整合性を提供しますが、当事者間の通信の機密性は提供しません。

TLS は TLS エンドポイント間の機密性を提供します。これにより署名データ自体が攻撃者によって取得されることを防ぎ、署名リプレイ(Section 7.2.2)を防ぐうえで重要です。

TLS を使用する場合は、[BCP195] に示された推奨に従って展開する必要があります。

7.2. メッセージ処理と選択

7.2.1. 不十分なカバレッジ

署名でカバーされていないメッセージの任意の部分は、攻撃者によって変更され得て、署名に影響を与えずに済んでしまいます。攻撃者はヘッダーフィールドやその他のメッセージコンポーネントを挿入または変更して、署名の範囲外でメッセージの処理を変更することができます。このように改変されたメッセージは署名検証に合格するかもしれませんが、検証者がメッセージ全体を処理するときに、署名されていない部分によって署名の信頼性が覆され、処理結果が変更されてしまいます。

これに対抗するために、本仕様を適用するアプリケーションは、アプリケーションと展開の制約内で可能な限り多くのメッセージ部分に署名することを要求すべきです。検証者は署名されたメッセージコンポーネントのみを信頼するべきであり、検証者はメッセージ処理を続ける前に署名されていない機微な部分を取り除くことも検討できます。

7.2.2. 署名のリプレイ

HTTP メッセージ署名はメッセージの部分集合に署名することを許すため、異なる 2 つの HTTP メッセージが同じ署名で検証される可能性があります。最も極端な例は、いかなるメッセージコンポーネントにも署名していない署名です。そのような署名が傍受されれば、攻撃者は任意の HTTP メッセージにそれを付けて自由にリプレイできます。十分なコンポーネントカバレッジがあっても、ある署名が 2 つの類似した HTTP メッセージに適用されると、署名が保持されたままメッセージがリプレイされる可能性があります。

このような攻撃に対抗するために、まず署名者は他のメッセージと区別できるように十分なメッセージ部分をカバーするべきです。さらに、署名は nonce 署名パラメータを用いてメッセージごとの一意な値を提供し、検証者が同じ nonce 値の繰り返しを検出して署名のリプレイを見つけられるようにできます。さらに署名者は署名の作成時刻と署名が失効する時刻を提供して、捕獲された署名値の有用性を制限できます。

もし検証者が署名者から新しい署名を発行させたい場合、Accept-Signature ヘッダーフィールドを新しい nonce パラメータと共に送信できます。単に署名をリプレイしている攻撃者は、選択された nonce 値で新しい署名を生成することはできません。

7.2.3. 署名するメッセージコンポーネントの選択

HTTP メッセージ署名を適用する際、どのメッセージコンポーネントを署名の対象とするかを決定する必要があります。アプリケーションによっては、中継者によって検証前に変更されることが想定されるコンポーネントがあります。これらのコンポーネントをカバーすると、その変更によって意図的に署名が破られることになります。

しかしながら、本書はどのコンポーネントに署名するかを柔軟に決められるようにしており、各アプリケーションは問題のあるコンポーネントを避けつつ適切な部分に署名することができます。例えば、クエリパラメータをリライトする Web アプリケーションフレームワークは、@query 導出コンポーネントを使う代わりに @query-param 導出コンポーネントでクエリ値を部分的に参照することを選ぶかもしれません。

一部のコンポーネントは中継者によって変更されることが期待されるため、通常は署名すべきではありません。例として Via や Forwarded ヘッダーはプロキシやその他のミドルボックスによって操作され、既存の値を置き換えたり完全に削除したりすることが予想されます。これらのフィールドは非常に限定的で緊密に連携されたシナリオを除いて署名の対象とすべきではありません。

署名の側面を選択するための追加の考慮事項は Section 1.4 に記述されています。

7.2.4. HTTP フィールドではなく署名パラメータや導出コンポーネントを選ぶこと

いくつかの HTTP フィールドには、HTTP 署名パラメータや導出コンポーネントと類似した値や解釈があります。多くの場合、フィールドではない代替手段に署名する方が望ましいです。特に次のフィールドは、アプリケーションが明確に必要としない限り通常署名に含めるべきではありません:

"date"
Date ヘッダーフィールドの値は HTTP メッセージのタイムスタンプを表しますが、署名自身の作成時刻は created 署名パラメータにエンコードされます。これら 2 つの値は、署名および HTTP メッセージの作成・直列化方法に応じて異なる場合があります。署名の有効時間ウィンドウを処理するアプリケーションは、その計算に created 署名パラメータを使用すべきです。アプリケーションは Date フィールドと created パラメータ間の許容できるずれの限界を設定することもできます。詳しくは 7.2.2 および 7.2.1 を参照してください。
"host"
Host ヘッダーフィールドは HTTP/1.1 固有のもので、その機能は @authority 導出コンポーネント(Section 2.2.3)に包含されています。異なる HTTP バージョン間で値を保持するために、アプリケーションは常に @authority 導出コンポーネントを使用すべきです。詳細は Section 7.5.4 を参照してください。

7.2.5. 署名ラベル

HTTP メッセージ署名値は、Signature および Signature-Input フィールド値内の一意のラベルによって識別されます。これらのラベルは署名値をメッセージに添付する際に選択されるものであり、署名処理そのものには考慮されません。仲介者はメッセージ処理中に既存の署名をリラベルしても構いません。

したがって、アプリケーションは特定のラベルの存在に依存すべきではなく、ラベル自体に意味論的な意味を持たせるべきではありません。必要な追加の意味は追加の署名パラメータを用いて、署名に付与しカバーすることができます。特に tag パラメータは Section 7.2.7 に記載されるようなアプリケーション固有の値を定義するために用いることができます。

7.2.6. 複数署名による混乱

複数の署名を 1 つのメッセージに適用できるため(Section 4.3)、攻撃者がキャプチャしたメッセージに自分の署名を追加して既存の署名を変更せずに済ませることが可能です。この新しい署名は攻撃者の鍵に基づいて完全に有効であるか、あるいは何らかの理由で無効な署名であるかもしれません。これらの各状況に対して対処が必要です。

一連の有効な署名を処理する検証者は、署名者(署名鍵によって識別される)をすべて考慮する必要があります。期待される署名者からの署名のみを、署名の暗号的妥当性にかかわらず受け入れるべきです。

メッセージ上の一連の署名を処理する検証者は、どのように扱うかを決定する必要があります。もし少なくとも一つの署名が有効であればメッセージを受け入れる設計であれば、検証者は有効な署名の前に無効な署名を削除して処理を続けることができます。逆に、単一の無効な署名によりメッセージを拒否する設計だと、攻撃者は有効な署名に無効な署名を注入してサービス拒否を引き起こすことができます。

7.2.7. アプリケーション固有署名タグの衝突

複数のアプリケーションやプロトコルが同じメッセージに同時に HTTP 署名を適用することがあります。実際、これは多くの状況で望ましい機能です(Section 4.3 を参照)。単純な検証者は複数署名の処理中に混乱し、関連のないまたは無関係な署名に基づいてメッセージを受け入れたり拒否したりする可能性があります。アプリケーションが自分の処理に適用される署名を選択するのを助けるために、アプリケーションは tag 署名パラメータの特定値を宣言することができます(Section 2.3 を参照)。例えば、アプリケーションゲートウェイを対象とする署名は、そのアプリケーションの署名パラメータとして tag="app-gateway" を要求することができます。

tag パラメータの使用は、攻撃者が同じ値をターゲットアプリケーションとしても使用するのを妨げるものではありません。パラメータ値は公開され制限がないためです。その結果、検証者はどの署名をチェックするかを限定するために tag パラメータの値のみを用いるべきです。各署名は十分なカバレッジが提供されているかどうかを確認するために検証者によって個別に検査される必要があります(Section 7.2.1 を参照)。

7.2.8. メッセージコンテンツ

本仕様単体では、リクエストまたはレスポンスのいずれに対しても、署名の下で HTTP メッセージのコンテンツを直接カバーするものではありません。ただし、[DIGEST] はコンテンツの暗号学的ダイジェストをフィールドに表現するための一連のフィールドを定義しています。一度このフィールドが作成されれば、それは Section 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 値で新しい署名を適用する必要があります。これは Section 4.3 のリバースプロキシ使用例に類似しています。

req パラメータ(Section 2.4)を使用するアプリケーションは、この機能の制限を認識する必要があります。具体的には、クライアントがリクエストに Content-Digest ヘッダーフィールドのようなものを含めない場合、サーバーはそのリクエストのコンテンツをカバーする署名を含めることができません。

7.3. 暗号に関する考慮事項

7.3.1. 暗号と署名衝突

本書は独自の暗号プリミティブを定義せず、代わりに他の仕様に依拠してこれらの要素を定義します。もし署名アルゴリズムや署名ベースの処理に使用される鍵が攻撃に対して脆弱である場合、生成される署名も同じ攻撃に対して脆弱になります。

署名システムに対する一般的な攻撃は署名衝突を強いることであり、同じ署名値が複数の異なる入力に対して成功裏に検証される状況です。本仕様は HTTP メッセージから署名ベースを再構築し、署名対象のコンポーネント一覧が署名内で固定されるため、衝突を効果的に行うのは難しいですが不可能ではありません。攻撃者は衝突を有効にするために HTTP メッセージとそのカバーされたコンポーネントを操作する必要があります。

これに対抗するために、HTTP メッセージに署名する際は検証済みの鍵と署名アルゴリズムのみを使用するべきです。"HTTP Signature Algorithms" レジストリは、アプリケーションがメッセージに適用するための信頼できる署名アルゴリズムの一つの情報源となります。

署名パラメータ値や署名値自体を個別に置換することは可能ですが、署名ベース生成アルゴリズム(Section 2.5)は常に署名パラメータを署名ベースの最後の値として決定論的な直列化方法でカバーします。このステップにより署名パラメータと署名値が強く結び付けられ、攻撃者が署名ベースの一部を部分的に置換することを困難にします。

7.3.2. 鍵の窃取

署名ベースの暗号システムの基本的な前提は、署名鍵が攻撃者によって漏洩していないことです。もしメッセージの署名に使用される鍵が外部に持ち出されたり盗まれたりすると、攻撃者はその鍵を用いて自身の署名を生成できるようになります。したがって署名者は署名鍵素材を漏洩、取得および攻撃者の使用から保護しなければなりません。

これに対抗するために、署名者は鍵を時間とともにローテーションして盗まれた鍵が有効である時間を制限することができます。署名者は鍵エスクローや安全な鍵保管システムを使用して鍵に対する攻撃面を制限することもできます。さらに、非対称署名アルゴリズムを使用すると対称アルゴリズムよりも鍵素材の露出が少なくなります(Section 7.3.3 を参照)。

7.3.3. 対称暗号

本書は非対称および対称の両方の暗号を HTTP メッセージに適用することを許容します。性質上、対称暗号方式は署名者と検証者が同一の鍵素材を知っていることを要求します。これは、検証者が有効な署名を生成できることを意味します。もし検証者が侵害されれば、攻撃者は署名者になりすますことが可能になります。

可能な場合は非対称方式や安全な鍵合意メカニズムを使用してこの種の攻撃を回避するべきです。対称方式を使用する場合、鍵素材の配布はシステム全体で保護する必要があります。一つの手法は検証プロセス(および鍵素材)を他のコードから分離する別個の暗号モジュールを使用して攻撃面を最小化することです。別の手法は、署名者と検証者が直接鍵値を共有せずに各メッセージのための一意の鍵を合意するための鍵導出関数を使用することです。

さらに、システム内で対称アルゴリズムが許容される場合は、鍵仕様ダウングレード攻撃を回避するために特別な注意が必要です(Section 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 パラメータ(Section 2.4)や複数署名(Section 4.3)をメッセージに適用する際、既存の Signature フィールドの値を署名することで、既存署名のバイトを新しい署名の値に含めることが可能です。一見するとこの慣行は元の署名の下のコンポーネントを可検証に帰属的にカバーするように見えますが、[JACKSON2019] で説明される攻撃を用いて、無関係なメッセージ上で署名出力値を偽装することが可能です。

以下の例では、Alice が Bob に署名付きリクエストを送信し、Bob は Alice の受信メッセージに応答していることを証明する署名付きレスポンスを Alice に返したいとします。Mallory はこのトラフィックを傍受して Alice のメッセージを自分のものに差し替え、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 は自分のリクエスト Req_M に対して、かつその署名のバイト値が元の Sig_A と完全に一致するような署名キー Key_M_Sign を作成し、有効な署名 Sig_M を生成できるようにする。
  6. Mallory は Req_MSig_M と共に Bob に送信する。
  7. Bob は Mallory の検証鍵 Key_M_Verify に対して Sig_M を検証する。Bob は自分が Alice に応答しているとは全く考えていない。
  8. Bob は Req_M に対するレスポンス Res_B を作成し、自分の鍵 Key_B_Sign を用いてこのメッセージに対する署名 Sig_B を作成する。Bob は Sig_B のカバーされたコンポーネントに Sig_M の値を含めるが、リクエストメッセージから他の部分を含めない。
  9. Mallory は Bob からのレスポンス Res_BSig_B を含む)を受け取り、これを Alice にリプレイする。
  10. Alice は Mallory から Res_B を受け取り、Bob の検証鍵 Key_B_Verify を用いて Sig_B を検証する。Alice は自分の元の署名 Sig_A のバイトを署名ベースに含め、署名が検証される。
  11. Alice は Bob が自分のメッセージに応答したと信じ、これが起こったという暗号学的証拠を得たと誤認するが、実際には Bob は Mallory の悪意あるリクエストに応答しており、Alice はそれに気付かない。

これを軽減するために、Bob はリクエストメッセージの署名フィールドだけでなくより多くの部分に署名することができ、Alice のメッセージと Mallory のメッセージをより明確に区別できるようにします。特に非否認目的でこの機能を使用するアプリケーションは、元の署名で必要とされている任意のコンポーネントも二次署名で別途カバーすることを規定することができます。署名されたメッセージに対しては、第一署名の対応する Signature-Input フィールドのカバレッジを要求することにより、nonce やタイムスタンプのような一意の項目も第二の署名で十分にカバーされることを保証できます。

7.4. 署名パラメータを対象メッセージに一致させる

7.4.1. 必須メッセージパラメータの変更

攻撃者は、本来無害な署名パラメータや署名済みメッセージコンポーネントを変更することで、実質的にサービス拒否を引き起こすことができます。変更されたメッセージを拒否することが望ましい挙動ではありますが、署名検証が継続的に失敗すると、(1) システムを再稼働させるために検証者が署名チェックを無効にしてしまう(Section 7.1.1 を参照)か、または (2) アプリケーションが署名対象コンポーネントに関する要件を最小化してしまう可能性があります。

アプリケーション内でそのような失敗が頻繁に発生する場合、署名者と検証者はお互いに生成した署名ベースを比較して、メッセージのどの部分が変更されているかを特定するべきです。想定される変更が見つかった場合、署名者と検証者は合格するための代替要件に合意することができます。ただし、攻撃者によるコンポーネント改変が疑われる場合に、その変更されたコンポーネントの署名要件を削除すべきではありません。

7.4.2. カバーされたコンポーネントの値と対象メッセージ内の値の一致

検証者は、署名されたメッセージコンポーネントがメッセージ自体の値と一致していることを確認する必要があります。例えば、@method 導出コンポーネントは、署名ベース内の値がこのメッセージを提示する際に使用された HTTP メソッドと同じであることを要求します。本仕様は、検証者がメッセージから署名ベースを導出することを義務付けることでこれを促進しますが、怠惰なキャッシュや生の署名ベースを処理サブシステムに渡すような運用により、提示された署名と一致しないメッセージを下流の検証者が受け入れてしまう可能性があります。

これに対処するために、署名ベースを生成するコンポーネントは、システム内の署名者と検証者の両方から信頼される必要があります。

7.4.3. メッセージコンポーネントのソースとコンテキスト

メッセージコンポーネント値を導出するための署名コンテキストには、対象の HTTP メッセージ自体、関連するメッセージ(例えばレスポンスを引き起こしたリクエスト)、および署名者または検証者がアクセスできる追加情報が含まれます。署名者と検証者の双方が署名ベース用のコンポーネント値を作成するときに、すべての情報の出所を慎重に検討し、信頼できないソースから情報を取得しないよう注意する必要があります。そうでないと、攻撃者はこのように緩く定義されたメッセージコンテキストを利用して、署名ベース文字列に自らの値を注入し、意図した値を上書きまたは破損させる可能性があります。

例えばほとんどの状況では、メッセージの対象 URI は [HTTP]Section 7.1 に定義されているようなものです。ただし、あるアプリケーションが受信リクエストの @authority を署名することを要求する一方で、その処理を行うアプリケーションがリバースプロキシの背後にあるとしましょう。そのようなアプリケーションは @authority 値の変化を想定し、プロキシの向こう側にいるクライアントから見た外部のターゲット URI を知るように構成されているかもしれません。このアプリケーションは、その構成済みの値を @authority のようなメッセージコンポーネント値を導出する際のターゲット URI として使用することができます。

このアプローチは問題がないわけではなく、誤設定されたシステムが別のシステムコンポーネント向けに意図された署名付きリクエストを受け入れてしまう可能性があります。このシナリオでは、仲介者が代わりに自らの署名を追加してアプリケーションが直接検証できるようにすることができます(Section 4.3 に示すとおり)。この代替アプローチはより積極的な仲介者を必要としますが、ターゲットアプリケーションが外部の構成値を知ることに頼る度合いを減らします。

別の例として、Section 2.4 は、レスポンスメッセージを署名すると同時にレスポンスを引き起こしたリクエストメッセージの一部を含める方法を定義しています。この場合、コンポーネント値計算のコンテキストは、署名が適用される単一のメッセージだけではなく、レスポンスとリクエストの組合せです。この機能のために、req フラグは、署名者がコンポーネント識別子の値のためにどのコンテキスト部分がソースになっているかを明示的に示すことを可能にします。実装は、各コンポーネントについて意図されたメッセージのみが参照されていることを確実にする必要があります。さもないと、攻撃者が一方または他方を操作して署名を破壊しようとする可能性があります。

7.4.4. 複数のメッセージコンポーネントコンテキスト

署名済みメッセージ内でメッセージコンポーネント値を導出するためのコンテキストが、それぞれの署名ごとに異なることはあり得ます。これは特に、プロキシがメッセージを変更して変更後の値に対して署名を追加する場合に当てはまります。例えば、リバースプロキシがリクエスト中の公開ホスト名を、転送先の各サービスホスト用のホスト名に置き換えることができます。クライアントとリバースプロキシの両方が @authority をカバーする署名を追加する場合、サービスホストはリクエスト上で 2 つの署名を目にし、それぞれが @authority コンポーネントに対して異なる値を署名していることになります。これはメッセージがクライアントからサービスホストへ移動する過程でそのコンポーネントが変化したことを反映しています。

そのような場合、内部サービスが署名のうちどちらか一方のみを検証するか、あるいは Section 7.4.3 で述べた外部構成情報を使用するのが一般的です。しかしながら、両方の署名を処理する検証者は、それぞれの署名に対して異なるメッセージコンポーネントコンテキストを使用する必要があります。なぜなら @authority コンポーネントの値は署名ごとに異なるからです。そのような検証者は、受信メッセージに対するリバースプロキシのコンテキストと、リバースプロキシから来るメッセージに対するターゲットサービスのコンテキストの両方を認識している必要があります。検証者は適切なコンテキストを適切な署名に適用するよう特に注意を払う必要があります。さもないと攻撃者はこの複雑な構成の知識を利用して検証者への入力を混乱させる可能性があります。

そのような検証者はまた、署名間のメッセージコンポーネントコンテキストの差異が予期され許容されるものであることを確認する必要があります。例えば前述のシナリオでは、リバースプロキシが元のホスト名を Forwarded ヘッダーフィールドに含め、@authority、forwarded、およびクライアントのエントリを Signature フィールドで署名することができます。検証者は Forwarded ヘッダのホスト名を使用して、そのホスト名が期待どおりに変換されていることを確認できます。

7.5. HTTP 処理

7.5.1. 無効な HTTP フィールド名を導出コンポーネント名として処理すること

HTTP フィールド名の定義では、名前のどの位置でも @ 文字の使用は許可されていません。したがって、すべての導出コンポーネント名は @ 文字で始まるため、これらの名前空間は完全に分離されるべきです。しかし、一部の HTTP 実装はフィールド名で許容される文字に十分厳密ではないことがあります。そのような実装では、送信者(または攻撃者)が @ 文字で始まるヘッダーフィールドを注入し、それがアプリケーションコードに渡される可能性があります。これらの無効なヘッダは導出メッセージ内容の一部を上書きして任意の値を差し替えるのに使われ得るため、攻撃者に署名衝突(Section 7.3.1)攻撃やその他の機能的置換攻撃(例えば GET リクエストの署名を細工した POST リクエストで使用するなど)を仕掛ける余地を与える可能性があります。

これに対抗するため、メッセージコンポーネントの値を選択する際、コンポーネント名が @ 文字で始まる場合は、それを導出コンポーネントとして処理し、決して HTTP フィールドとして処理してはなりません。コンポーネント名が @ 文字で始まらない場合にのみ、メッセージのフィールドから値を取得できます。Section 2.5 で述べられるアルゴリズムは安全な処理順序を提供します。

7.5.2. 意味的に等価なフィールド値

署名ベース生成アルゴリズム(Section 2.5)は、HTTP フィールドの値をそのコンポーネント値として使用します。通常は、これは署名者と検証者の両方でフィールド値の実際のバイト列をコンポーネント値として取ることを意味します。しかし、一部のフィールド値は、その値自体のバイト列を変更する意味的に等価な変換を許容する場合があります。例えば、フィールド定義は値の一部またはすべてを大文字小文字を区別しないと宣言したり、内部の空白文字の特別な扱いを持たせたりできます。また、Via ヘッダのコメント削除のように中継者による想定される変換を持つフィールドもあります。そのような場合、検証者は署名者が使用したバイト列と異なる等価に変換されたフィールド値を使用してしまい、検証が失敗する可能性があります。検証者にとってはこの種のエラーの検出は困難です。なぜならフィールド値はアプリケーション上は許容されるままだからです。

そのようなフィールドを処理する際、署名者と検証者は変換をどのように扱うかを合意する必要があります。ひとつの選択肢は問題のあるフィールドに署名しないことですが、その場合でもアプリケーションに対して十分な署名カバレッジが残るよう注意する必要があります(Section 7.2.1 を参照)。もう一つの選択肢は、フィールドを HTTP メッセージに追加する前にフィールドのアプリケーション固有の正規化値を定義することです(例えば内部コメントを常に削除してから署名する、あるいは常に小文字に変換するなど)。これらの変換はフィールドが署名ベース生成アルゴリズムへの入力として使用される前に適用されるので、署名ベースはメッセージ内に表示されるバイト値をそのまま含むことになります。もし変換がメッセージから値を抽出した後に署名ベースに追加する前に適用されると、値置換攻撃のような別の攻撃面が生じ得ます。すべてのアプリケーション固有の追加規則は本仕様の範囲外であり、その性質上、これらの変換はその特定アプリケーション外での相互運用性を損なう可能性があります。可能な限りこうした追加規則の使用は避けることが推奨されます。

7.5.3. 構造化フィールド値の解析

本仕様のいくつかの部分は、Structured Field 値の解析([STRUCTURED-FIELDS])に依存しています。特に、HTTP Structured Field 値の厳密な直列化(Section 2.1.1)、Dictionary Structured Field のメンバー参照(Section 2.1.2)、および署名検証時の @signature-input 値の処理(Section 3.2)。Structured Field 値は比較的解析が容易に設計されていますが、そのようなパーサの単純または壊れた実装は、実装に微妙な攻撃面を露呈させる可能性があります。

例えば、もし @signature-input 値のバグのあるパーサがリスト内の文字列値の引用符の正しい閉じを強制しない場合、攻撃者はこれを悪用してメッセージの Signature-Input 値を操作し、署名ベースに追加の内容を注入する可能性があります。

これに対抗するため、実装は署名側および検証側の両方で、すべての Structured Field 処理に対して完全準拠で信頼できるパーサを使用するべきです。

7.5.4. HTTP バージョンとコンポーネントの曖昧性

一部のメッセージコンポーネントは HTTP のバージョンによって異なる方法で表現されます。例えば、リクエストターゲットのオーソリティは HTTP/1.1 では Host ヘッダーフィールドで送信されますが、HTTP/2 では :authority 疑似ヘッダで送信されます。署名者が HTTP/1.1 メッセージを送り Host ヘッダフィールドに署名したが、メッセージが検証者に届く前に HTTP/2 に変換された場合、Host ヘッダが削除される可能性があり、署名は検証されなくなります。

このため、HTTP メッセージ署名は特定の値を取得する単一の方法を定義する導出コンポーネント群を定義しています。例えば Host ヘッダの代わりに @authority 導出コンポーネント(Section 2.2.3)などです。可能な限りこのような選択肢には導出コンポーネントを優先して使用するべきです。

7.5.5. 正規化に関する攻撃

署名ベースの生成に曖昧さがあると、攻撃者に署名を置換または破壊する手段を与える可能性があります。特に HTTP フィールド値は、壊れた実装により予期せぬ挙動を引き起こす可能性があります。本仕様の単純な実装は、フィールドの単一の値をそのまま直接コンポーネント値として使用するような処理をしてしまいがちです。

例えば obs-fold フィールド値の扱いで内部の行折返しや空白を除去しないと、署名ベースに余分な改行が署名者によって導入され、署名衝突(Section 7.3.1)攻撃の足掛かりになる可能性があります。あるいは、複数回現れるヘッダーフィールドが本仕様で要求されるように単一の文字列値に結合されない場合、署名されたコンポーネント値が署名ベースに複数回現れ、それを置換または攻撃される可能性があります。

これに対処するため、フィールド値処理アルゴリズム全体を署名者および検証者のすべての実装で実装する必要があります。

7.5.6. リストでないフィールド値

単一のメッセージで HTTP フィールドが複数回現れる場合、これらの値は署名ベースに含めるために単一の一行文字列値に結合する必要があります(Section 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] によるリスト構文に準拠しない内部構文を定義しています。特に一部の部分は引用符無しのコンマを許容し、複数のクッキーを送信する場合は通常複数の個別のフィールド行として送信されます。同じメッセージで複数の Set-Cookie フィールドが送信される場合、それらを単一行に結合して解析・使用できるようにすることは一般に不可能です([HTTP]Section 5.3 を参照)。したがって、すべてのクッキーは別々のフィールド値から処理する必要があり、署名ベースはこの目的専用に生成された特別な結合値から処理されるべきです。もしクッキー値が無効であれば、署名されたメッセージは拒否されるべきです。これは Section 7.5.7 にあるパディング攻撃の可能性と関連します。

これに対処するため、アプリケーションは Set-Cookie のような問題のあるフィールドの署名を制限することを選択できます。例えば単一のフィールド値が存在し、その結果が曖昧でない場合にのみフィールドを署名に含めるといった方法です。署名者はまた bs パラメータを使用してそのようなフィールドを保護することもできます(Section 2.1.3 を参照)。

7.5.7. 複数フィールド値を用いたパディング攻撃

HTTP フィールド値は HTTP 署名ベースに含めるために単一の文字列値に結合する必要があるため(Section 2.5 を参照)、攻撃者が特定のフィールドに追加の値を注入して検証者の署名ベースにこれを加える可能性があります。

ほとんどの状況では、これは新しい署名ベース値が署名者の生成したものと一致しないために期待どおり署名検証が失敗します。しかし理論的には、攻撃者があるフィールドにゴミ値を注入し、別のフィールドに所望の値を注入して特定の入力を強制する可能性があります。これは攻撃者が既存のフィールド値に付け加えることで変更を達成するという点で、Section 7.3.1 に記述された衝突攻撃の変形です。

これに対抗するため、アプリケーションは署名でカバーされたフィールドの内容を検証するとともに署名自体が検証されることを保証する必要があります。そのような保護により、攻撃者のパディング攻撃は、攻撃者が署名衝突を強制できた場合でもフィールド値プロセッサによって拒否されます。

7.5.8. クエリ要素の曖昧な扱い

Section 5 の HTML フォームパラメータ形式([HTMLURL])は広く展開され、多くのアプリケーションフレームワークによってサポートされています。便宜上、これらのフレームワークのいくつかは、HTTP クエリ内で見つかったクエリパラメータと、特に Content-Type が "application/x-www-form-urlencoded" の POST メッセージのメッセージ本文内で見つかるものを結合することがあります。@query-param 導出コンポーネント識別子(Section 2.2.8 参照)は、リクエストのターゲット URI のクエリ部分からのみ値を抽出します。したがって、攻撃者が署名済みクエリパラメータを未署名のフォームパラメータで上書きする、またはその逆により署名済みクエリパラメータを覆い隠すことが可能となり得ます。

これに対処するため、アプリケーションは署名ベースおよびアプリケーションで使用される値が一貫したコンテキスト(この場合はターゲット URI のクエリ成分)から取得されることを確認する必要があります。さらに、HTTP リクエストにコンテンツがある場合は、Section 7.2.8 で述べたようにメッセージコンテンツ自体にも署名することを検討すべきです。


8. プライバシーに関する考慮事項

8.1. 鍵による識別

もし署名者が複数の検証者に対して同じ鍵を使用するか、単一の検証者に対して時間を通じて同じ鍵を使用する場合、その鍵の継続的な使用によって署名者は検証者の集合全体にわたって追跡され得ます。暗号鍵は機能的に一意であることが意図されているため、同じ鍵を長期間使用することは複数のメッセージに同一の当事者が署名している強い指標になります。

多くのアプリケーションではこれは望ましい特性であり、HTTP メッセージ署名を署名者を検証者に対して認証する一部として使用できることを可能にします。しかしながら、署名者が気付かない意図しない追跡につながる可能性もあります。この種の追跡に対抗するため、署名者は通信している各検証者ごとに異なる鍵を使用するか、あるいは与えられた検証者にメッセージを送る際に鍵をローテーションすることができます。これらの方法は他の反トラッキング技術の必要性を否定するものではありません。

8.2. 署名は機密性を提供しない

HTTP メッセージ署名は、署名によって保護される情報に対して機密性を提供しません。HTTP メッセージの内容、すべてのフィールドの値、および署名値自体は、メッセージにアクセスできる任意の当事者に平文で提示されます。

輸送レベルでの機密性を提供するためには、Section 7.1.2 で述べられているように TLS または同等の手段を使用できます。

8.3. オラクル(情報漏洩の危険)

エラー条件に関して開発者に有用なフィードバックを提供する必要性と、攻撃者に追加情報を与えないようにする必要性のバランスを取ることが重要です。例えば、無邪気で役立つサーバ実装がリソース要求に必要な鍵識別子を示そうとするかもしれません。もし誰かがその鍵を誰が管理しているかを知れば、リソースの存在と鍵で識別される当事者の間に相関関係を作ることができます。そのような情報へのアクセスは攻撃者が正当なリソース所有者をさらなる攻撃の標的にするために利用することができます。

8.4. 必須のコンテンツ

本仕様の中核的設計理念は、署名でカバーされるすべてのメッセージコンポーネントが、検証者が署名ベースを再作成し署名を検証するために利用可能である必要があるということです。その結果、本仕様の適用が特定のフィールドの署名を要求する場合、検証者はそのフィールドの値にアクセスする必要があります。

例えば、仲介プロセッサを含む複雑なシステムでは、署名を壊すことを恐れて仲介者がプライバシーに敏感な情報をメッセージから削除できなくなるような驚くべき挙動を引き起こす可能性があります。この特定の状況を緩和する一つの方法は、仲介者自身が署名を検証し、その後メッセージを変更してプライバシーに敏感な情報を削除することです。仲介者はこの時点で自身の署名を追加して、次の宛先に対して受信した署名が検証されたことを示すことができます。これは Section 4.3 の例に示されています。

9. References

9.1. Normative References

[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. 参考資料(Informative References)

[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」、作業中の文書、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」、作業中の文書、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>。

Appendix A. HTTP メッセージ署名の検出

過去に非標準的な署名付き HTTP メッセージ(この仕様で使用される Signature フィールドの他の定義を含む)を作ろうとする試みが多数ありました。本仕様や他の公開文書、あるいは過去のドラフト版をサポートしたい開発者は、互換性の問題が予期しない問題を引き起こす可能性があるため、慎重かつ意図的に対応することが推奨されます。

実装者はまずこの仕様で定義される Signature-Input フィールドを検出・検証して、本ドキュメントで記述された仕組みが使用されているか、それとも代替の仕組みであるかを判別することを推奨します。Signature-Input フィールドが存在する場合は、すべての Signature フィールドを解析し、本仕様の文脈で解釈できます。


Appendix B. 例(Examples)

以下の非規範的な例は、HTTP メッセージ署名の実装をテストするために提供されます。示された署名付きメッセージは、記載されたパラメータで署名ベースを作成し、示されたアルゴリズムと鍵を使用して署名を生成するために使用できます。

示された秘密鍵は署名の生成に使用できますが、示されたアルゴリズムのいくつかは非決定論的であるため、署名の結果は例のバイト列と異なることが期待されます。公開鍵はすべての署名例の検証に使用できます。

B.1. 例示鍵(Example Keys)

この節では、文書内の例示署名で参照される暗号鍵を示します。これらの鍵はテスト以外の目的で使用してはなりません(MUST NOT)。

各鍵の鍵識別子は本仕様の例全体で使用されます。これらの例において、署名者と検証者はここで使用されるすべての鍵識別子を一意に参照でき、使用される鍵とアルゴリズムが署名が提示される文脈に適していることが前提とされています。

各秘密鍵の構成要素は PEM 形式で示されます([RFC7468])。表示するには次の OpenSSL コマンドを実行します:

openssl pkey -text

このコマンドは OpenSSL バージョン 1.1.1m ですべての例示鍵でテストされました。いくつかのシステムではこれらの鍵を直接生成または使用できない場合があり、追加の処理が必要になることがあります。すべての鍵は JWK 形式でも利用可能です。

B.1.1. RSA 例示鍵(Example RSA Key)

以下の鍵は 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 例示鍵(Example RSA-PSS Key)

以下の鍵は 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 例示鍵(Example ECC P-256 Test Key)

以下の鍵は曲線 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 例示鍵(Example Ed25519 Test Key)

以下の鍵は 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. 共有シークレットの例(Example Shared Secret)

以下の共有シークレットはランダムに生成された 64 バイトを Base64 エンコードしたもので、本書では 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 のいくつかの追加コンポーネント(オーソリティ、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 の適用可能なすべてのメッセージコンポーネント(content-type と length を含む)および多くの導出コンポーネントをカバーします。ここでも 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 終端プロキシに次のリクエストを行います:

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": :MIIBqDCCAU6gAwIBAgIBBzAKBggqhkjOPQQDAjA6MRswGQYDVQQ\
  KDBJMZXQncyBBdXRoZW50aWNhdGUxGzAZBgNVBAMMEkxBIEludGVybWVkaWF0ZSBD\
  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 に変更し、オーソリティを "example.com"(Host ヘッダ内)に変更しています。メソッドとオーソリティの両方が署名でカバーされているため、同じ署名はもはや有効ではありません:

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 ヘッダーフィールドの 2 つのインスタンスの順序を入れ替えています。同じ名前のフィールドの順序は 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] に基づいています。編集者は、その Internet-Draft の著者である 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、および Jeffrey Yasskin。


著者の連絡先

Annabelle Backman (編集者)
Amazon
P.O. Box 81226
Seattle, WA 98108-1226
アメリカ合衆国
電子メール: richanna@amazon.com
URI: https://www.amazon.com/
Justin Richer (編集者)
Bespoke Engineering
電子メール: ietf@justin.richer.org
URI: https://bspk.io/
Manu Sporny
Digital Bazaar
203 Roanoke Street W.
Blacksburg, VA 24060
アメリカ合衆国
電子メール: msporny@digitalbazaar.com