HTTP/2 HPACKの深淵:パケットの「無駄」を削ぎ落とすアルゴリズムの哲学
ネットワークエンジニアとして現場に立つと、たかだか数バイトのヘッダーがどれほどの重荷になるか、骨身に染みて理解する時が来る。HTTP/1.1時代、我々はUser-AgentやCookieといった肥大化するテキストヘッダーを、そのままTCPのウィンドウに押し込んできた。RTT(Round Trip Time)が支配する広域ネットワークにおいて、この「冗長な文字列」は遅延という名の死刑宣告に等しい。
そこで登場したのが、HTTP/2の心臓部とも言える「HPACK」だ。今回は、単なる規格の解説ではなく、パケットがワイヤー上を駆け巡る際の挙動と、そこに潜むセキュリティの罠について、技術者の視点で深く掘り下げていく。
—
HPACKのメカニズム:静的テーブルと動的テーブルの「記憶」
HPACKの凄みは、一言で言えば「文脈の共有」にある。クライアントとサーバーが「前に送った情報は、次に送る必要はない」という合意形成を行うことで、ヘッダーを劇的に圧縮する。
1. 静的テーブル (Static Table)
あらかじめ定義された61個の頻出ヘッダー(例: :method: GET や path: /)をインデックス化している。これはプロトコルレベルで固定されているため、ネゴシエーション不要で即座に参照できる「共通言語」だ。
2. 動的テーブル (Dynamic Table)
これが真骨頂だ。通信の過程で現れた新しいヘッダー(例: x-auth-tokenなど)を、接続ごとのメモリ空間にキャッシュする。以降、同じヘッダーが現れたら、その値を送る代わりに「テーブルの何番目」という整数値だけで済ませる。
もし、貴方のインフラでHTTP/2のパフォーマンスが伸び悩んでいるなら、まずはこの動的テーブルのサイズ設定(SETTINGS_HEADER_TABLE_SIZE)を疑うべきだ。
# NginxでHPACKの動的テーブルサイズを最適化する設定例
http {
# デフォルトは4KB。メモリに余裕があり、リクエストヘッダーが巨大な環境では
# 8KB〜16KBに引き上げることで、再送コストを削減できる。
http2_max_field_size 16k;
http2_chunk_size 8k;
}
—
ネットワーク層から見たパケットの挙動
HPACKは、TCPの「ストリーム」という概念を最大限に活用する。注意が必要なのは、HPACKはTLS層のさらに内側で実行されるという点だ。
TLSハンドシェイクが完了し、ALPN(Application-Layer Protocol Negotiation)によってh2が選択された瞬間から、パケットは「HPACKによる圧縮」と「TCPのストリーム多重化」の恩恵を受ける。ここで重要なのが、TCPバッファのチューニングだ。HPACKでヘッダーが小さくなれば、MTU(Maximum Transmission Unit)内に収まるペイロードの割合が増え、セグメントの断片化が抑制される。
以下のカーネルパラメーター設定は、HTTP/2の多重化を支えるための基本的な布石となる。
# TCPウィンドウのスケーリングを有効化し、帯域幅遅延積(BDP)を最大化する
sysctl -w net.ipv4.tcp_window_scaling=1
# バッファの最大値を引き上げ、多重化による滞留を防ぐ
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
—
セキュリティの暗部:HPACKの脆弱性「CRIME」と「HPACK Bomb」
しかし、圧縮には常に脆弱性が付きまとう。かつてのCRIME攻撃と同様、HPACKの動的テーブルもまた、攻撃者にとっては「観測可能な差分」となり得る。
特に注意すべきは「HPACK Bomb(HPACK爆弾)」だ。攻撃者は、極端に高い圧縮率を持つヘッダーを送りつけることで、サーバー側のデコード処理(メモリ展開)に異常なCPU負荷をかけ、DoS攻撃を仕掛けてくる。
防御の鉄則
1. テーブルサイズの制限: サーバー側で受け入れる動的テーブルのサイズを厳格に制限する。
2. ヘッダーの最大長制限: h2_max_header_sizeなどを設定し、際限のないメモリ消費を防ぐ。
3. 推論ベースの攻撃への対策: 重要なCookieや認証トークンを含むヘッダーは、動的テーブルに追加させない(あるいは秘匿性を高める)実装を検討すること。
—
最後に:エンジニアが向き合うべき「最適化」
HPACKは、ネットワークの物理的な制約(帯域と遅延)を、計算資源(CPUとメモリ)で解決するトレードオフの産物だ。我々インフラエンジニアがやるべきことは、ただ規格に従うことではない。
サーバーのパケットキャプチャをtsharkで開き、HPACKのインデックスが正しく再利用されているか、あるいは動的テーブルが頻繁にフラッシュ(全クリア)されていないかを確認してほしい。もしテーブルの更新頻度が高すぎるなら、それはアプリケーション側のヘッダー設計が「揮発的すぎる」ことを意味する。
# tsharkでHPACKの圧縮率を簡易的に確認するためのフィルタ例
tshark -r capture.pcap -Y "http2.type == HEADERS" -T fields -e http2.header.name -e http2.header.value
技術の深淵を覗くことは、パケットの呼吸を感じることと同義だ。HTTP/2のヘッダー圧縮という小さな最適化の積み重ねこそが、現代の高速なWeb体験を支える唯一の正攻法なのである。
コメント