Apache HTTPD 2.2.21 における変更点 (CVE-2011-3192 Range header DoS 対策)

やっと出たので動作差分です。主に2.2.20でエンバグして修正された点が主になります。
現時点ではまだリリースノートは更新されていませんが、開発者によるGA投票通過して
ミラーもされてるので引っ込む事は無いでしょう。
ともあれ今回の件はこれで最後になるといいなぁ。


アドバイザリはこちら。(2011/09/14 ドラフトから正式版に張り替え)
大きな変更としては1.3系が影響対象外になった旨が記載されています。


Rangeリクエスト関連の処理で2.2.19から動作が変わった点は以下です。
2番目と4番目は本質的には同じでしたが、実際にバグを踏んだ例があったので
分離しています。
リグレッションした箇所だけ直して終わりかと思ったら結構変わったようです。

  • 1. 32区間を超える応答にてContent-Lengthヘッダが使用されなくなった
    • 2.2.19 全区間Content-Lengthヘッダでの応答
    • 2.2.20 32区間を境界値としてchunkedでの応答へ変わるようになった
    • 2.2.21 2.2.20同様
  • 2. 合計値がコンテンツサイズを超える複数区間要求を処理しなくなった
    • 2.2.19 要求した通りに返す
    • 2.2.20 コンテンツサイズを超える場合はRangeヘッダを無視
    • 2.2.21 2.2.20同様
  • 3. 負値のみを指定した場合の動作が変更された
    • 2.2.19 負値として扱う末尾からのデータが返る (RFC的に正しい動作)
    • 2.2.20 始点区間無しとして扱い先頭のデータが返る (リグレッション)
    • 2.2.21 2.2.19同様
  • 4. Rangeリクエストで全区間要求した場合にレスポンスコードが異なる
    • 2.2.19 206のレスポンスとして応答 (訂正 こっちがRFC的に推奨される動作)
    • 2.2.20 200でAccept-Rangesヘッダ付きレスポンスとして応答 (206でSHOULDなので一応違反ではない)
    • 2.2.21 2.2.20同様
  • 5. 不正な区間を指定した場合の動作が変更
    • 2.2.19 416としてエラー
    • 2.2.20 200として全区間を返す
    • 2.2.21 2.2.19同様
  • 6. MaxRangesディレクティブが追加
    • 2.2.19 存在しない
    • 2.2.20 存在しない
    • 2.2.21 指定した値以上の区間数はRangeヘッダを無視 (未指定の場合は200区間)

1と2は2.2.20と変わっていないので詳細は省略します。


3. 負値のみを指定した場合の動作が変更された
普通にバグっていたというオチですね。
踏んでる人見かけなかったのでこんな使い方してる人は殆ど居ないのかもしれません。

## リクエスト
GET /xxxx HTTP/1.1
Host: xxxx
Range: bytes=-10
## 2.2.20 のレスポンス (終点のみ指定された物として扱われる)
HTTP/1.1 206 Partial Content
Content-Length: 11
Content-Range: bytes 0-10/1000
## 2.2.19, 2.2.21のレスポンス (負の値として扱われて後ろの部分が返ってくる)
HTTP/1.1 206 Partial Content
Content-Length: 10
Content-Range: bytes 990-999/1000
...


4. Rangeリクエストで全区間要求した場合にレスポンスコードが異なる
trunkのコードでは2.2.19の動作へ戻されてましたが、最終的には2.2.20の動作になりました。
報告者のケースは206の応答をRangeサポートの判別に使っていた様ですが、結論としては
レスポンスのAccept-Rangesヘッダで判別せよという事になったみたいです。
RFC的には2.2.20以降の200で応答する動作が正しいようです。
(訂正 RFC的には206でSHOULDでした。該当箇所はRFC 2616の14.35.1 Byte Ranges)

## リクエスト
GET /xxxx HTTP/1.1
Host: xxxx
Range: bytes=0-
## 2.2.19 のレスポンス 206で全区間が返る
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: 1000
Content-Range: bytes 0-999/1000
...
## 2.2.20, 2.2.21 のレスポンス 200で全区間が返る
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 1000
...


5. 不正な区間を指定した場合の動作が変更
コンテンツサイズが要求した値を超えている場合にエラーが返るようになりました。
2.2.20で動作が変わって元に戻ったパターンですね。
# 前回に2.2.20の変更点挙げたときには漏れてました

## リクエスト (対象コンテンツは1000bytes)
GET /xxxx HTTP/1.1
Host: xxxx
Range: bytes=10000-
## 2.2.19, 2.2.21 のレスポンス 416でエラー
HTTP/1.1 416 Requested Range Not Satisfiable
...
## 2.2.20 のレスポンス 200で全区間が返る
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 1000
...


6. MaxRangesディレクティブが追加
許可する区間数を設定で決められるようになりました。
2.2.21で設定できる値との対応は以下の通りです。
設定値の扱いをどうするか最後まで検討していたようで、httpd.confのコメント
と一致しない部分がありますがそのうち直るでしょう。(0がunlimitedと書かれているが違う)

設定値 意味
指定無し デフォルト(200区間まで許可)
default デフォルト(200区間まで許可)
none Rangeを許可しない(ヘッダ削除と同じ)
unlimited 制限無し(今まで通り)
1以上の数値 指定した区間数まで許可

指定した値前後の応答は以下の通りです。

## リクエスト
GET /xxxx HTTP/1.1
Host: xxxx
Range: bytes=0-1,1-2,3-4,...
## 制限を超過した場合のレスポンス
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: xxxxx
...
## 制限に収まってる場合のレスポンス
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: xxxxx
Content-Type: multipart/byteranges; boundary=xxxxxxxxxx
...


2.2.20の変更点は前回も書いたとおり、このバージョンは急かされたからなのか結構なバグ
が混入していました。2.2.21はその後暫くバグ報告が無いか待ってからタグが打たれた訳ですが
アドバイザリの更新等も無かったため、2.2.20(各ディストリビューションのバックポートパッチ含む)が
そういう状態にあるという事を知らない人も多かったのではないでしょうか。


欲を言えば、2.2.20リリース後の数日で既にいくつかの問題に気づいていた訳ですし、以下を
アドバイザリのアップデートで公開してから、追加のバグ報告待ちに入った方が良かったと思いました。

  • 1.3.xは脆弱性の対象にならない
  • 2.2.20には問題があり修正した2.2.21を準備中

されていれば、問題を知らずに2.2.20へバージョンアップして、すぐに2.2.21へ
再度バージョンアップする羽目になる人も今よりは減ったんじゃないですかね。
結果として対象外になった1.3系の対応しようと頑張ってた人とかも同様で。