【セキュリティ】HTTP request smuggling(HRS)の脆弱性の原理と仕組みを理解する

投稿日: カテゴリー: セキュリティ
Pocket

RFCと現実の利用実体との差が埋められず生まれたHTTP request smuggling(HRS)の脆弱性

HTTP request smuggling(HRS)の脆弱性はContent-Length と Transfer-Encoding の解釈のズレを悪用して次に対応するリクエストを改ざんする攻撃手法です。HTTP Desync Attacksとも呼ばれます。
脆弱性が発生する原因となっているのはHTTP 仕様がリクエストの終了場所を指定する方法がContent-LengthとTransfer-Encodingヘッダーの2つ存在することです。
Content-Lengthはメッセージ本文の長さをバイトでリクエストの区切りと解釈します。
Transfer-Encoding:chunkedはかたまりに区切って連続的に送信する方式のため、チャンクの区切りをリクエストの区切りと解釈します。

RFC 2068には「Messages MUST NOT include both a Content-Length header field and the “chunked” transfer coding. If both are received, the Content-Length MUST be ignored.」と共存させちゃダメだけどもし両方きたらContent-Lengthの方を無視してくださいと書いてあります。

単体のサーバなら問題は発生しずらいのですが、複数で利用するヘッダーが異なる場合は定義通り統一されるとは限りません。

CL.TEパターン: フロントエンド サーバーはContent-Lengthヘッダーを使用し、バックエンド サーバーはTransfer-Encodingヘッダーを使用する
TE.CLパターン: フロントエンド サーバーはTransfer-Encodingヘッダーを使用し、バックエンド サーバーはContent-Lengthヘッダーを使用する

繰り返しますがHTTP request smuggling(HRS)の脆弱性の基本原理はContent-LengthとTransfer-Encodingヘッダー解釈の差を悪用したものです。

これに加えRFCに定義があったり、選べたり、そもそも言及がなかったりするリクエストパターンが存在し不整合が起きる要因を孕んでいます。

  • 定義: Transfer-Encoding + Content-Length など
  • 未定義: 複数の Content-Length など
  • 任意: GET + Content-Length など

RFCの定義の改修は進みContent-LengthとTransfer-Encodingヘッダー解釈差の脆弱性は徐々に少なくなってきましたが、

BurpSuiteで有名なPortSwiggerはHTTP Desync Attacksという新しい手法を生み出し、TE/CL の組み合わせ をベースにしつつも Transfer-Encoding 優先の挙動に不整合を起こさせることに成功しました。

パターン1
Transfer-Encoding: xchunked

パターン2
Transfer-Encoding: chunked
Transfer-Encoding: x
・・・・

パターン1が通用する理由としてはTransfer-Encoding: gzip, chunkedなど他の指定がある場合、chunkedの文字列がTransfer-Encoding:に含まれていればよいとする場合と厳密に検証している場合で解釈のずれが生まれていることが挙げられます。

抽象的な話が続きましたので、次に具体的な例で仕組みを示したいと思います。

実例のCL.TE HRSでHTTP request smuggling(HRS)の脆弱性の原理と仕組みを理解する

早速、実例で示していきます。CL.TE HRSに脆弱なサーバに以下のようなリクエストを送ると

1回目はステータス200、「2回目は」ステータス404が返ってきます。

実は2回目にサーバにリクエストされたのは以下のようなリクエストになっています。

なぜ、そんなことが起きるかというとContent-LengthとTransfer-Encodingのリクエスト解釈の差から

GET /404 HTTP/1.1
X-decoy: X(ここから次のリクエストが入る)

の部分がレスポンスされずサーバに残ります。

HTTP request smuggling(HRS)の脆弱性のリスクとは?

現象としては面白いけど、どのあたりがセキュリティリスクなのか初見はピンと来ない方も多いのではないでしょうか。

具体的には以下のような攻撃が可能です。

  • ヘッダーなどにトークンやアクセスキーを設定している場合、向き先を攻撃者サーバに変えられ漏洩する可能性がある
  • フロントエンドサーバでしかアクセス制御を実装していない場合、アクセス制御をバイパスできる可能性がある
  • 悪意あるコンテンツへの誘導(オープンリダイレクト含む)

まだまだ原理的な深掘りが足りない方は以下のドキュメントをチェックしてみましょう。

🔗HTTP Request Smugglingの Watchfire のホワイトペーパー

HTTP request smuggling(HRS)の脆弱性への対策

以下の2点を抑えることが基本になります。

  • HTTP/2にして、ダウングレードされないようにする(特にフォワード プロキシではバックエンド(upstream)でHTTP/2が有効になっているか確認する)
  • リクエストボディが想定されない場所でリクエストボディが送られてきた場合を受け付けない実装を行う
  • フロントエンドとバックエンド間での Keep Alive を無効にする
  • CRLF インジェクションの対策を行う

低減策では「Content-Length」ヘッダと「Transfer-Encoding」ヘッダが両方ともセットされた場合リクエストを拒否するのも有効です。
AWS ALBでは「HTTP Desync 緩和モードが」があるのでこれを設定することも検討しましょう。

以下の動画では機能の紹介とHTTP Desync Attacksの説明がよく纏まっていて参考になるのでチェックしてみましょう。

以上です。参考になれば幸いです。