【実務・中級編】RetryパケットによるDoS攻撃対策 – HTTPプロトコル・通信規格実践ガイド

なぜQUICは「UDP」を選んだのか?――Retryパケットが守る、Webの最前線

ネットワークエンジニアとして現場を歩いていると、「HTTP/3は速い」という枕詞を耳にタコができるほど聞かされます。しかし、その「速さ」の裏側で、OSI参照モデルの再定義とも言えるような血の滲むようなセキュリティ対策が行われていることを意識している人は意外と少ない。

TCPの「3ウェイ・ハンドシェイク」という安全神話から離れ、QUICがUDPという「素っ裸のプロトコル」を選んだとき、真っ先に立ちはだかった壁がIPアドレス偽装によるリソース枯渇攻撃(DoS攻撃)です。今回は、この防波堤の要である「Retryパケット」の真実を紐解いていきましょう。

—

1. UDPという「諸刃の剣」とRetryパケットの使命

TCPであれば、SYNパケットに対してSYN-ACKを返し、クライアントがACKを返すまで接続は確立しません。しかし、UDPは接続概念を持たない。攻撃者が送信元IPを偽装して大量の`Initial`パケット(QUICの接続開始パケット)を送りつければ、サーバー側は応答パケットを生成するためにメモリを消費し、瞬く間にリソースが枯渇します。

ここで登場するのがRetryパケットです。サーバーは、「本当にそのIPアドレスの持ち主か?」を確証するまで、接続リソースを一切消費しません。

サーバーが「Retry」をトリガーする条件

サーバーが `Retry` パケットを返すのは、攻撃の兆候を検知したとき、あるいは単に「サーバーのリソースを保護したい」と判断したときです。具体的には、クライアントからの最初の `Initial` パケットに含まれる `Token` が空であるか、無効である場合に発動します。

—

2. 通信フロー:Retryパケットによる「身元確認」の全貌

Retryパケットが介在するハンドシェイクのシーケンスは、以下のようになります。

1. Client → Server: `Initial`パケット送信(Tokenは空)。
2. Server → Client: `Retry`パケット送信(検証用トークンと、元のパケットを検証するための情報が含まれる)。
3. Client → Server: `Initial`パケット再送(今度は受け取ったTokenを付与)。
4. Server → Client: トークンを検証し、正当と認めれば`Initial`パケット(Server Helloなど)を返し、本格的なハンドシェイクへ。

この仕組みの肝は、サーバー側がステートレスであることです。サーバーは最初の通信で一切の状態を保持せず、ただ「Token」を投げ返すだけ。クライアントがそのTokenを返して初めて、サーバーは「このIPは本物だ」と認め、コネクションの状態管理を開始します。

—

3. 実務で確認する:Retryパケットの挙動

実際に開発環境で、QUICのハンドシェイクをデバッグする際は、`qlog` や `wireshark` を使うのが定石です。

Wiresharkでの確認ポイント

Wiresharkのフィルタに `quic.type == 0x03` (Retryパケットを示すタイプ値)を入力してください。ここに現れるパケットの中身を見ると、以下のような重要なパラメータが確認できます。

  • Retry Token: サーバーが生成した暗号化トークン。クライアントはこれをそのまま次のパケットにコピーして送り返す義務があります。
  • Retry Integrity Tag: このパケットが改ざんされていないことを保証する認証タグ。

Python (aiocoap/aioquic) を使った接続テスト

`aioquic` を使って、サーバー側がRetryを強制する設定(`retry=True`)にした場合の挙動をシミュレーションしてみましょう。

aioquicでのサーバー側設定イメージ
from aioquic.quic.configuration import QuicConfiguration

configuration = QuicConfiguration(is_server=True)
ここをTrueにすると、全ての接続でRetryパケットを要求する
開発環境での耐DoSテストに必須
configuration.retry = True

サーバー証明書のロード等の定型処理は省略

—

4. エンジニアが知るべき「現場のTips」

運用現場で「HTTP/3の接続確立に異常な遅延がある」というトラブルに直面した際、以下のチェックリストを頭に入れておいてください。

  • Path MTUとRetryパケット:

Retryパケットが含まれることでInitialパケットのサイズが大きくなり、MTU(最大転送単位)を超過してパケットロスが発生することがあります。特にVPN環境や特殊なISP経路では、Initialパケットがフラグメンテーションを起こしていないか確認してください。

  • Tokenの有効期限:

サーバー側で生成したTokenのライフタイムが短すぎると、クライアントが再送した時には既に無効になっているケースがあります。API設計時にCDNやロードバランサーを挟んでいる場合、これらのヘッダー変換でTokenが破損していないか注視が必要です。

  • curlでのデバッグ:

クライアント側の挙動を確認するには、以下のコマンドが最も手っ取り早いです。

HTTP/3通信の詳細をトレースする
–http3 はQUICを使用するフラグ
curl -v –http3 https://your-api-server.com/ 2>&1 | grep “QUIC”

—

最後に:ネットワークは「信頼」をどう設計するか

Retryパケットは、単なるエラーメッセージではありません。それは「見知らぬ誰かを信用する前に、その足跡を確かめる」という、デジタル空間における現代的な作法です。

HTTP/3を扱うということは、こうした低レイヤーの防衛線を理解した上でトラフィックを流すことに他なりません。単に「速いライブラリを使う」だけでなく、なぜそのプロトコルがそのような挙動をするのか。その理屈を理解してこそ、真のインフラストラクチャ・スペシャリストと呼べるのではないでしょうか。

次回は、このQUICの「0-RTT」が抱えるリプレイ攻撃のリスクと、その対策について深掘りしていこうと思います。現場のネットワークは常に動いています。プロトコルの進化に置いていかれないよう、パケットの呼吸を感じ取り続けていきましょう。

コメント

タイトルとURLをコピーしました