このブログ記事では、HTTP/2プロトコルに関連して最近発見された脆弱性を取り上げます。特定の条件下では、この脆弱性が悪用され、HTTP/2仕様のサーバー側機能を実装するNGINX Open Source、NGINX Plus、および関連製品に対してサービス拒否攻撃が実行される可能性があります。この攻撃からシステムを保護するため、NGINX構成を直ちに更新することを推奨します。
HTTP/2ストリームのリセットに関する問題
サーバーとの接続が確立されると、HTTP/2プロトコルでは、クライアントがデータ交換用の複数のストリームを同時に開始できます。以前のバージョンのプロトコルとは異なり、エンドユーザーが別のページに移動した場合や、その他の理由でデータ交換を停止した場合、HTTP/2ではストリームをキャンセルできます。これは、サーバーにRST_STREAMフレームを送信することで行われ、サーバーが不要な処理を実行せずに済みます。
この脆弱性は、確立済みの接続上で多数のHTTP/2ストリームを開始して即座にキャンセルし、サーバーの最大同時ストリーム数の制限を回避することで悪用されます。これは、後続のストリームが到着するよりも速く受信ストリームがリセットされるため、クライアントが設定済みのしきい値に達することなくサーバーを過負荷状態にできることに起因します。
NGINXへの影響
パフォーマンスとリソース消費を考慮し、NGINXでは同時ストリーム数のデフォルト上限を128に設定しています(http2_max_concurrent_streamsを参照)。また、ネットワークとサーバーのパフォーマンスを最適なバランスに保つため、NGINXではHTTPキープアライブを使用して、クライアントがデフォルトで最大1,000リクエストまでHTTP接続を維持できるようにしています(keepalive_requestsを参照)。
デフォルトのkeepalive上限を利用することで、NGINXはこの種の攻撃を防ぎます。この上限を回避するために追加の接続を作成すると、標準的なレイヤー4の監視ツールやアラートツールによって悪意のある攻撃者が検知されます。
ただし、NGINXのkeepaliveがデフォルトの推奨設定よりも大幅に高い値に設定されている場合、この攻撃によってシステムリソースが枯渇する可能性があります。ストリームがリセットされると、HTTP/2プロトコルでは、そのストリーム上で以降のデータをクライアントに返さないことが求められます。通常、リセットによって発生するサーバーのオーバーヘッドは、キャンセルを適切に処理するタスクによるごくわずかなものです。しかし、NGINXのストリームしきい値を回避すると、クライアントは数千ものストリームを短時間に開始することで、このオーバーヘッドを利用して増幅できます。その結果、サーバーのCPU使用率が急上昇し、正規のクライアントに対するサービスが妨害されます。
異常に高いkeepalive上限の下でHTTP/2ストリームを確立し、その後ストリームをキャンセルすることによるサービス拒否。
攻撃にさらされるリスクを軽減する手順
フル機能のサーバーおよびプロキシであるNGINXは、サービス拒否攻撃を緩和するための強力なツールを管理者に提供します。これらの機能を活用し、サーバーの攻撃対象領域を最小限に抑えるには、NGINXの設定ファイルに以下の変更を加えることが不可欠です。
- keepalive_requestsは、デフォルト設定の1,000リクエストのままにしてください
- http2_max_concurrent_streamsは、デフォルト設定の128ストリームのままにしてください
また、ベストプラクティスとして、以下の安全対策を追加することを推奨します。
- limit_connは、単一のクライアントから許可される接続数に上限を適用します。このディレクティブは、アプリケーションのパフォーマンスとセキュリティのバランスを考慮した適切な設定で追加することを推奨します。
- limit_reqは、単一のクライアントから一定時間内に処理されるリクエスト数を制限します。このディレクティブは、アプリケーションのパフォーマンスとセキュリティのバランスを考慮し、適切な値を設定して追加してください。
F5の対応
複数の緩和策を検証したことで、この攻撃が幅広いお客さまやユーザーにどのような影響を及ぼす可能性があるかを把握できました。この調査により、NGINXには攻撃を回避するために必要なツールがすべてすでに備わっていることを確認しましたが、推奨仕様を超えてNGINXを構成する必要があるユーザーも確実に対応できるよう、追加の対策を講じることにしました。
調査の結果、HTTP/2プロトコル上で理論的に発生し得るさまざまなフラッド攻撃に対して、サーバーのレジリエンスを向上させる方法が明らかになりました。これを受け、こうした状況下でシステムの安定性を高めるパッチをリリースしました。このような脅威から保護するため、NGINX Open Sourceユーザーは最新のコードベースからバイナリを再ビルドし、NGINX Plusをご利用のお客さまは直ちに最新パッケージ(R29p1またはR30p1)へ更新することを推奨します。
パッチの仕組み
NGINXに対するフラッド攻撃を早期に検出できるように、このパッチでは、1回のイベントループ内で新たに開始できるストリーム数に上限を設けています。この上限は、http2_max_concurrent_streamsディレクティブで設定した値の2倍です。この攻撃のように、リクエストの送信直後にストリームがリセットされ、最大しきい値に達しない場合でも、この上限が適用されます。
影響を受ける製品
この脆弱性は、NGINX HTTP/2モジュール(ngx_http_v2_module)に影響します。影響を受ける可能性がある特定のNGINXまたはF5製品については、次のページをご覧ください:https://my.f5.com/manage/s/article/K000137106。
CVE-2023-44487(HTTP/2 Rapid Reset攻撃)の詳細については、以下をご覧ください。https://www.cve.org/CVERecord?id=CVE-2023-44487
謝辞
この脆弱性の発見、特定、緩和に向けた協力において、Cloudflare、Amazon、Googleが果たした役割に謝意を表します。
関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります