メインコンテンツまでスキップ

7. セキュリティ上の考慮事項 (Security Considerations)

このセクションでは、QPACK に関するセキュリティ上の潜在的な懸念事項について説明します:

  • 共有圧縮コンテキストに圧縮される秘密に関する推測を検証するための長さベースのオラクルとしての圧縮の使用。

  • デコーダでの処理またはメモリ容量の枯渇から生じるサービス拒否。

7.1 動的テーブル状態のプローブ (Probing Dynamic Table State)

QPACK は、HTTP のようなプロトコルに固有の冗長性を利用することにより、フィールドセクションのエンコードされたサイズを削減します。この究極の目標は、HTTP リクエストまたはレスポンスを送信するために必要なデータ量を削減することです。

ヘッダーフィールドとトレーラーフィールドをエンコードするために使用される圧縮コンテキストは、エンコードして送信するフィールドを定義でき、エンコードされた後のこれらのフィールドの長さを観察できる攻撃者によってプローブされる可能性があります。攻撃者が両方を実行できる場合、動的テーブル状態に関する推測を確認するためにリクエストを適応的に変更できます。推測がより短い長さに圧縮される場合、攻撃者はエンコードされた長さを観察し、推測が正しいと推測できます。

これは、Transport Layer Security プロトコル([TLS])および QUIC トランスポートプロトコル([QUIC-TRANSPORT])でも可能です。TLS と QUIC はコンテンツの機密性保護を提供しますが、そのコンテンツの長さに対しては限られた保護しか提供しないためです。

注意: パディングスキームは、これらの機能を持つ攻撃者に対して限られた保護のみを提供し、特定の推測に関連する長さを学習するための推測回数の増加のみを強制する可能性があります。パディングスキームは、送信されるビット数を増やすことで圧縮に直接作用します。

CRIME([CRIME])のような攻撃は、これらの一般的な攻撃者の能力の存在を実証しました。特定の攻撃は、DEFLATE([RFC1951])がプレフィックスマッチングに基づいて冗長性を削除するという事実を利用しました。これにより、攻撃者は一度に 1 文字ずつ推測を確認でき、指数時間攻撃を線形時間攻撃に減らすことができました。

7.1.1 QPACK と HTTP への適用性 (Applicability to QPACK and HTTP)

QPACK は、推測が個々の文字ではなくフィールド行全体に一致することを強制することにより、CRIME([CRIME])をモデルにした攻撃を軽減しますが、完全には防止しません。攻撃者は推測が正しいかどうかのみを知ることができるため、攻撃者は特定のフィールド名に関連付けられたフィールド値のブルートフォース推測に削減されます。

したがって、特定のフィールド値を回復する実行可能性は、値のエントロピーに依存します。その結果、高エントロピーの値は正常に回復される可能性は低くなります。ただし、低エントロピーの値は依然として脆弱です。

この性質の攻撃は、相互に不信のある 2 つのエンティティが単一の HTTP/3 接続に配置されたリクエストまたはレスポンスを制御するたびに可能です。共有 QPACK コンプレッサーが 1 つのエンティティが動的テーブルにエントリを追加でき、もう 1 つのエンティティが選択したフィールド行をエンコードする際にそれらのエントリを参照できる場合、攻撃者(2 番目のエンティティ)はエンコードされた出力の長さを観察することにより、テーブルの状態を学習できます。

たとえば、相互に不信のあるエンティティからのリクエストまたはレスポンスは、仲介者が次のいずれかを行う場合に発生する可能性があります:

  • 複数のクライアントからのリクエストを単一の接続でオリジンサーバーに送信する、または

  • 複数のオリジンサーバーからのレスポンスを取得し、クライアントへの共有接続に配置する。

Web ブラウザーは、異なる Web オリジン([RFC6454])からの同じ接続で行われたリクエストが相互に不信のあるエンティティによって行われたと仮定する必要もあります。相互に不信のあるエンティティを含む他のシナリオも可能です。

7.1.2 軽減 (Mitigation)

ヘッダーフィールドまたはトレーラーフィールドの機密性を必要とする HTTP のユーザーは、推測を実行不可能にするのに十分なエントロピーを持つ値を使用できます。ただし、これはすべての HTTP のユーザーが攻撃を軽減するための措置を講じることを強制するため、一般的な解決策としては実用的ではありません。HTTP の使用方法に新しい制約を課すことになります。

HTTP のユーザーに制約を課すのではなく、QPACK の実装は、動的テーブルプローブの可能性を制限するために圧縮の適用方法を制約できます。

理想的なソリューションは、メッセージを構築するエンティティに基づいて動的テーブルへのアクセスを分離します。テーブルに追加されるフィールド値はエンティティに帰属し、特定の値を作成したエンティティのみがその値を抽出できます。

このオプションの圧縮パフォーマンスを向上させるために、特定のエントリをパブリックとしてタグ付けできます。たとえば、Web ブラウザーは、すべてのリクエストで Accept-Encoding ヘッダーフィールドの値を使用可能にする可能性があります。

フィールド値の出所についての知識が不十分なエンコーダーは、代わりに、同じフィールド名と異なる値を持つ多くのフィールド行にペナルティを導入する可能性があります。このペナルティにより、フィールド値を推測しようとする多数の試みが、将来のメッセージでフィールドが動的テーブルエントリと比較されなくなり、さらなる推測を効果的に防ぐ可能性があります。

この応答は、フィールド値の長さに反比例する可能性があります。特定のフィールド名の動的テーブルへのアクセスを無効にすることは、より長い値よりも短い値でより迅速にまたはより高い確率で発生する可能性があります。

この軽減策は、2 つのエンドポイント間で最も効果的です。メッセージが、特定のメッセージを構築したエンティティに関する知識なしに仲介者によって再エンコードされる場合、仲介者は、元のエンコーダーが特に分離していた圧縮コンテキストを誤ってマージする可能性があります。

注意: テーブルからフィールドに対応するエントリを単純に削除することは、攻撃者が値を再インストールさせる信頼できる方法を持っている場合、効果がない可能性があります。たとえば、Web ブラウザーで画像を読み込むリクエストには、通常、Cookie ヘッダーフィールド(この種の攻撃の潜在的に非常に価値の高いターゲット)が含まれ、Web サイトは画像の読み込みを簡単に強制でき、動的テーブルのエントリを更新できます。

7.1.3 インデックス化されないリテラル (Never-Indexed Literals)

実装は、機密フィールドを圧縮せず、代わりにその値をリテラルとしてエンコードすることによって保護することも選択できます。

フィールド行を動的テーブルに挿入しないことは、すべてのホップで回避される場合にのみ効果的です。インデックス化されないリテラルビット(セクション 4.5.4 を参照)は、特定の値が意図的にリテラルとして送信されたことを仲介者に通知するために使用できます。

仲介者は、'N' ビットが設定されたリテラル表現を使用する値を、それをインデックス化する別の表現で再エンコードしてはなりません(MUST NOT)。QPACK が再エンコードに使用される場合、'N' ビットが設定されたリテラル表現を使用しなければなりません(MUST)。HPACK が再エンコードに使用される場合、インデックス化されないリテラル表現([RFC7541] のセクション 6.2.3 を参照)を使用しなければなりません(MUST)。

フィールド値をインデックス化すべきではないとマークする選択は、いくつかの要因に依存します。QPACK はフィールド値全体を推測することから保護しないため、短いまたは低エントロピーの値は敵対者によってより容易に回復されます。したがって、エンコーダーは低エントロピーの値をインデックス化しないことを選択する可能性があります。

エンコーダーは、Cookie や Authorization ヘッダーフィールドなど、非常に価値が高いか回復に敏感であると考えられるフィールドの値をインデックス化しないことも選択する可能性があります。

逆に、エンコーダーは、公開された場合に価値がほとんどまたはまったくないフィールドの値のインデックス化を好む場合があります。たとえば、User-Agent ヘッダーフィールドは通常、リクエスト間で変化せず、任意のサーバーに送信されます。その場合、特定の User-Agent 値が使用されたという確認はほとんど価値を提供しません。

インデックス化されないリテラル表現を使用することを決定するためのこれらの基準は、新しい攻撃が発見されるにつれて時間とともに進化することに注意してください。

7.2 静的 Huffman エンコーディング (Static Huffman Encoding)

静的 Huffman エンコーディングに対する現在知られている攻撃はありません。ある研究では、静的 Huffman エンコーディングテーブルの使用が情報漏洩を生み出すことが示されましたが、この同じ研究では、攻撃者がこの情報漏洩を利用して意味のある量の情報を回復できないと結論付けました([PETAL] を参照)。

7.3 メモリ消費 (Memory Consumption)

攻撃者は、エンドポイントにメモリを枯渇させようとする可能性があります。QPACK は、エンドポイントによって割り当てられるピークと安定した両方のメモリ量を制限するように設計されています。

QPACK は、動的テーブルの最大サイズとブロックされたストリームの最大数の定義を使用して、エンコーダーがデコーダーに消費させることができるメモリ量を制限します。HTTP/3 では、これらの値は、それぞれ SETTINGS_QPACK_MAX_TABLE_CAPACITY および SETTINGS_QPACK_BLOCKED_STREAMS パラメータを介してデコーダーによって制御されます(セクション 3.2.3 およびセクション 2.1.2 を参照)。動的テーブルのサイズの制限は、動的テーブルに格納されているデータのサイズに加えて、オーバーヘッドの小さな許容量を考慮します。ブロックされたストリームの数の制限は、デコーダーに必要な最大メモリ量のプロキシにすぎません。実際の最大メモリ量は、デコーダーが各ブロックされたストリームを追跡するために使用するメモリ量に依存します。

デコーダーは、動的テーブルの最大サイズに適切な値を設定することにより、動的テーブルに使用される状態メモリの量を制限できます。HTTP/3 では、これは SETTINGS_QPACK_MAX_TABLE_CAPACITY パラメータに適切な値を設定することによって実現されます。エンコーダーは、デコーダーが許可するよりも小さい動的テーブルサイズを選択し、これをデコーダーに通知することにより、使用する状態メモリの量を制限できます(セクション 4.3.1 を参照)。

デコーダーは、ブロックされたストリームの最大数に適切な値を設定することにより、ブロックされたストリームに使用される状態メモリの量を制限できます。HTTP/3 では、これは SETTINGS_QPACK_BLOCKED_STREAMS パラメータに適切な値を設定することによって実現されます。ブロックされるリスクのあるストリームは、エンコーダーで追加の状態メモリを消費しません。

エンコーダーは、未確認のフィールドセクション内のすべての動的テーブル参照を追跡するためにメモリを割り当てます。実装は、追跡したい数だけ動的テーブルへの参照を使用することにより、状態メモリの量を直接制限できます。デコーダーへのシグナリングは必要ありません。ただし、動的テーブルへの参照を制限すると、圧縮効率が低下します。

エンコーダーまたはデコーダーによって消費される一時メモリの量は、フィールド行を順次処理することによって制限できます。デコーダー実装は、フィールドセクションをデコードしている間、フィールド行の完全なリストを保持する必要はありません。エンコーダー実装は、シングルパスアルゴリズムを使用している場合、フィールドセクションをエンコードしている間、フィールド行の完全なリストを保持する必要はありません。アプリケーションが他の理由でフィールド行の完全なリストを保持する必要がある場合があることに注意してください。QPACK がこれを強制しない場合でも、アプリケーションの制約によりこれが必要になる場合があります。

動的テーブルのサイズに関する交渉された制限は、QPACK 実装によって消費される可能性のあるメモリの大部分を占めますが、フロー制御のためにすぐに送信できないデータはこの制限の影響を受けません。実装は、特にデコーダーストリームで送信されないデータのサイズを制限する必要があります。このストリームでは、送信する内容を選択する柔軟性が制限されています。送信されないデータの過剰に対する可能な応答には、ピアが新しいストリームを開く能力を制限すること、エンコーダーストリームからのみ読み取ること、または接続を閉じることが含まれます。

7.4 実装の制限 (Implementation Limits)

QPACK の実装は、整数の大きな値、整数の長いエンコーディング、または長い文字列リテラルがセキュリティの弱点を作成しないことを保証する必要があります。

実装は、整数に対して受け入れる値、およびエンコードされた長さの制限を設定する必要があります。セクション 4.1.1 を参照してください。同様に、文字列リテラルに対して受け入れる長さの制限を設定する必要があります。セクション 4.1.2 を参照してください。これらの制限は、HTTP 実装が受け入れるように構成できる最大の個別フィールドを処理するのに十分な大きさである必要があります(SHOULD)。

実装がデコードできるよりも大きい値に遭遇した場合、リクエストストリーム上の場合は QPACK_DECOMPRESSION_FAILED タイプのストリームエラーとして、エンコーダーストリームまたはデコーダーストリーム上の場合は適切なタイプの接続エラーとして扱わなければなりません(MUST)。