【目次】

  1. 1.はじめに
  2. 2.HTTP Desync とは
  3. 3.HTTP Desync に対応するためには
  4. 4.ALB及びCLBに追加された新機能
  5. 5.設定画面及び稼働確認
  6. 6.おわりに

    1.はじめに

    2020年8月17日( US 現地時間)に Application Load Balancer (ALB) および Classic Load Balancer (CLB) が HTTP Desync Mitigation Mode をサポートするようになりました。

    HTTP Desync による問題からアプリケーションを保護する新機能となります。

    公式情報:
    Application Load Balancer および Classic Load Balancer が Desync Mitigation Mode を導入して高度な防御を追加

    2.HTTP Desync とは

    以下 AWS の公式アナウンスからの抜粋です。

    現代のウェブアプリケーションは通常、クライアントとサーバー間の高速で信頼性の高い通信を保証する一連のプロキシで構築されています。これらのプロキシは、RFC 7230 準拠の HTTP/1.1 リクエストを解析するための標準的なメカニズムに従いますが、非準拠のリクエストを解析するときに解釈が異なる場合があります。チェーン内の異なるプロキシがリクエストの境界で一致しない可能性があり、そのため同じリクエストを処理しない可能性がある場合に、これらの解釈の違いが Desync を引き起こすことがあります。これにより、キュー内の次のリクエストの先頭に追加されてバックエンドにスマグリングされる可能性のある任意のメッセージが残る可能性があります。最終的に、リクエストスマグリングは、アプリケーションをリクエストキューまたはキャッシュポイズニングに対して脆弱にし、認証情報のハイジャックまたは不正なコマンドの実行につながる可能性があります。

    HTTP Desync はフロントエンドにプロキシや CDN 等が存在する構成の場合に発生します。フロントエンドとバックエンドで終端場所の認識が一致しないことで、図の橙色の部分が後続の通信に含まれることにより、何らかの不正な攻撃を受ける可能性があります。

    以下の例で言うと、フロントエンドが最初の content-length ヘッダーを優先し、バックエンドが2番目のヘッダーを優先する構成の場合、内部でフロントエンドは青色と橙色のデータをバックエンドに転送し、バックエンドは応答を発行する前に青色のコンテンツのみを読み取るという、フロントとバックエンドでの解釈のズレ(Desync)が生じます。そして緑色のリクエストは意図しない情報(橙色)が含まれ、予期しない応答が返されることとなります。

    POST / HTTP/1.1
    Host: example.com
    Content-Length: 6
    Content-Length: 5
    
    12345GPOST / HTTP/1.1
    Host: example.com
    …
    

    参考情報:
    HTTP Desync Attacks: Request Smuggling Reborn

    3.HTTP Desync に対応するためには

    HTTP Desync に対応するためには以下が考えられます。

    ・フロントエンドとバックエンド間での Keep Alive を無効にする
    ・バックエンドとの通信を HTTP/2 のみを使用する
    ・フロントエンドとバックエンドの構成を揃える

    サーバへの負荷や既存の構成の変更が必要であまり現実的ではないかもしれません。

    他には以下が考えられます。
    ・フロントエンドでリクエストをルーティングする前にあいまいな要求を正規化する
    ・フロントエンドで曖昧な通信に対して制限をかける

    今回の新機能では「フロントエンドで曖昧な通信に対して制限をかける」という対応が取られました。

    4.ALB 及び CLB に追加された新機能

    今回追加された新機能は ALB 及び CLB において、AWS オープンソースライブラリの HTTP Desync Guardian 使用してリクエストを分類し、指定したモードで決められた動作(許可 or ブロック)する機能となります。

    まずは HTTP リクエストの分類を確認しましょう。

    分類 説明
    Compliant(準拠) リクエストは RFC 7230 に準拠している
    Acceptable(許容可能) リクエストは RFC 7230 に準拠していないが、既知のセキュリティ上の脅威はない
    Ambiguous(曖昧) リクエストは RFC 7230 に準拠していないが、さまざまな Web サーバーやプロキシが異なる処理をする可能性があるため、リスクがある
    Severe(重大) リクエストは高いセキュリティリスクをもたらす。ロードバランサーはリクエストをブロックし、400 のレスポンスをクライアントに提供し、クライアントの接続を閉じる

    HTTP リクエストに対する アクションとして3つのモードから選択できます。
    デフォルトは「Defensive」です。

    (*)要求をルーティングしますが、クライアントとターゲットの接続を閉じます。

    5.設定画面及び稼働確認

    実際の設定画面は以下の通りでデフォルトは「防御的」となっています。
    今回のテストは「最も厳格」で行います。

    稼働確認の方法ですが、 Content-Length と Transfer-Encoding を両方含む場合でテストします。

    RFC7230 によると Transfer-Encoding ヘッダを含むメッセージに Content-Lengthヘッダ が含まれてはいけない(※)とあります。この仕様をもとに確認用の POST リクエストを組んでみましょう。


    (※)
    https://tools.ietf.org/html/rfc7230#section-3.3.2
    https://tools.ietf.org/html/rfc7230#section-3.3.3
    「Transfer-Encoding ヘッダを持たないとき, Content-Length ヘッダを使用できる」
    「Transfer-Encoding ヘッダを含む場合、Content-Length ヘッダを使用してはならない」
    「 Transfer-Encodingヘッダ、Content-Lengthヘッダの両方を持つ場合、 Transfer-Encoding が Content-Length を上書きする。 Content-Length ヘッダについては除去しなければならない。」


    curl -X POST -v http://XXXXXX-YYYYYYYY.ap-northeast-1.elb.amazonaws.com/
    

    レスポンス

    $ < HTTP/1.1 200 OK
    < Date: Mon, 24 Aug 2020 04:25:14 GMT
    < Content-Type: text/html; charset=UTF-8
    < Content-Length: 78
    < Connection: keep-alive
    < Server: Apache/2.4.41 ()
    < Upgrade: h2,h2c
    < Last-Modified: Thu, 16 Jan 2020 05:25:43 GMT
    < ETag: "4e-59c3b0e7abd89"
    < Accept-Ranges: bytes
    
    curl -X POST -H "Content-Length:0" -H "Transfer-Encoding:chunked" -v http://XXXXXX-YYYYYYYY.ap-northeast-1.elb.amazonaws.com/
    

    レスポンス

    < HTTP/1.1 400 Bad Request
    < Server: awselb/2.0
    < Date: Mon, 24 Aug 2020 04:27:26 GMT
    < Content-Type: text/html
    < Content-Length: 138
    < Connection: close
    

    想定通り、Content-Lengthヘッダ と Transfer-Encodingヘッダ を両方含むリクエストのため ステータスコード 400 のレスポンスが返りました。

    ALBのログはそれぞれ以下のようになりました。

    http 2020-08-24T05:02:05.237774Z app/XXXXXX/YYYYYYYYY 117.53.27.150:59615 10.1.102.245:80 0.044 0.003 0.000 200 200 118 355 "POST http://XXXXXX-YYYYYYYY.ap-northeast-1.elb.amazonaws.com:80/ HTTP/1.1" "curl/7.64.1" - - arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXX:targetgroup/XXXXXXX/YYYYYYYY "Root=1-5f4349cd-05d4422f48de891d1d41dc98" "-" "-" 0 2020-08-24T05:02:05.190000Z "waf,forward" "-" "-" "10.1.102.245:80" "200" "-" "-"
    http 2020-08-24T05:02:29.746927Z app/XXXXXX/YYYYYYYYY 117.53.27.150:59619 - -1 -1 -1 400 - 163 288 "POST http://XXXXXX-YYYYYYYY.ap-northeast-1.elb.amazonaws.com:80/ HTTP/1.1" "curl/7.64.1" - - - "-" "-" "-" - 2020-08-24T05:02:29.728000Z "-" "-" "-" "-" "-" "Ambiguous" "BothTeClPresent"
    

    ログの項目には"classification"と"classification_reason"が追加されています。
    該当したアクセスをみると"Ambiguous" "BothTeClPresent"となっています。
    どのようなアクセスに分類されたかとその理由が記載されます。
    Classification reasons は以下で確認できます。
    公式情報:
    Classification reasons

    6.おわりに

    以上が HTTP Desync の説明と、それに対処するために ALB と CLB で追加された新機能の紹介です。最新のRFCに準拠した構成をとることは大切な対策となります。本番に適用することで、これまでアクセスできていたリクエストに問題が発生する恐れもありますので Strictest(最も厳格)へ変更する場合は慎重に行ってください。