2018/08/13)追記:より新しい情報については間違いだらけのHTTPセッション管理とその対策をどうぞ。PHPには広く知られているにも関わらず放置されている既知のセキュリティ脆弱性が幾つかあります。Adoption)脆弱性です。この脆弱性は現在広く利用されているWebアプリケーションの安全性に、非常に大きな影響を与える脆弱性です。セッションアダプション脆弱性とはセッション固定化攻撃を可能とする脆弱性の一種です。セッションアダプションに脆弱なセッション管理システムは、ユーザ(ブラウザ)が送信してきた未初期化のセッションIDを受け入れ、セッションを初期化してしまいます。PHPに限らず、RailsやJavaのフレームワーク等、多くのWebフレームワークに発見されている脆弱性です。セッションアダプション脆弱性を利用すると、攻撃者は長期間に渡って他人のIDを使う成りすましが可能になる場合があります。IDを盗みたい犯罪者には利用価値の高い脆弱性です。いい加減)、というとんでも無いクッキーの仕様と組み合わせると、大量の他人のユーザセッションIDを取得(設定)し、成りすます事ができます。6.0に共通する脆弱性です。最近、影響範囲はかなり狭くなりましたが、まだまだ注意が必要な脆弱性であり、根本的な解決にはパッチと適切なセキュリティ対策が必要です。国別TLDの属性ドメインにクッキーが設定できるバグはFirefox2を最後に広く使われているブラウザにはこの「仕様」は無くなりました。Firefox3のリリースにより、国別TLDの属性ドメイン問題はやっと、ほぼ解決した、と言える状態になりました。Firefox2を利用されている方は早急にFirefox3にバージョンアップした方が良いでしょう。このブログをご覧の方でも1割ほどが、まだFirefox2です。国別TLDの属性ドメインにクッキーが設定できる問題は、少なくともFirefox2で修正されるべきでしたが、何故修正されなかったのか詳しい理由は知りません。.netなどのgTLDの独自ドメインで運用しているサイトはあまり影響を受けないので、脆弱性の危険性が誤解され、放置されていたのかも知れません。国別TLDの属性ドメインにクッキーが設定できるのも問題ですが、詳しくは後ほど説明しますが、古いブラウザは親ドメインのクッキーが優先されていましたが、最近のブラウザは子ドメインのクッキーが優先されるようになっています。この為、以前に比べて脆弱性の影響は随分減っています。ブラウザ開発側の対応も褒められたものではありませんが、PHP開発側の対応はさらに酷いです。Esser氏によりパッチ付きで修正案が提案されたのですが未だに修正されていません。5.2両方にセッションアダプション脆弱性を修正するよう、PHPセキュリティレスポンスチームに提案したのですが、予想通り修正されませんでした。脆弱性の危険性は説明したのですが、危険性を理解していないとしか思えません。直らないものは仕方が無いので各自で対処するしかありません。各自で対策できるよう、個人Wikiではパッチも公開しています。対処方法の前に、なぜこの脆弱性を最悪と考えているのか、理解していただく為に攻撃方法を紹介します。サブドメインレンタルサーバなどで独自にドメインを取得していない場合、サブドメインでサイトを区別している場合がよくあります。example.jpがレンタルサーバドメインでuserAやuserBのサイトはuserA.example.jpuserB.example.jpとなっているサービスが良くあります。ドメインに対してクッキーを設定できます。クッキーが設定されている場合、サブドメインのクッキーより優先されてしまう場合があります。クッキーを設定しないで下さい。全てのユーザに見えてしまいます」と記載されているところもあるようです。PHPのセッションモジュールのデフォルトセッション名のPHPSESSIDに適当な値を設定するとサブドメイン共通のセッションIDが作れてしまいます。セッション名を変えて機械的な攻撃を防いだとしても、サイトを覗けばセッション名が直ぐに分かってしまいます。ログイン時にsession_regenerate_id()を呼んでいても、セッションアダプションに脆弱なセッションモジュールでは意味がありません。親ドメインのクッキーが優先され、セッションIDは変わらない事があるからです。訪問すると、そのユーザ「固有」のPHPSESSIDを有効期限2038年で設定します。等、ログインできるサイトが無いか試すだけです。全体が危険にさらされる可能性があります。JavaScriptでクッキーの操作が可能だからです。この例では、example.jpを利用していますがFirefox2に対してはexampleの部分がco,ac,orでも同じ攻撃ができました。example.or.jpなどに共通のセッションIDを設定することが可能だったのです。この問題の影響範囲の大きさは説明する必要も無いと思います。狙い撃ち攻撃セッションアダプションに脆弱なPHPとその攻撃に対して脆弱なアプリケーションを利用すると、同僚や同級生など身近な人のセッションを乗っ取りは簡単です。クッキーは通常テキストファイルに保存されています。サービスを利用しているとします。2038年まで有効なセッションIDを書くだけです。クッキーファイルは編集可能なので、隙を見て編集するだけです。有効期限を比較的短めに設定すればキーロガーのように証拠も残りませんし、ネットワークに不審なパケットも流れません。セッションアダプションに脆弱なPHPを利用しているなら、session_regenerate_id()を呼び出しているPHPアプリでも攻撃できます。クッキーを保存しているファイルを読み込み専用にするだけで、セッションIDクッキーの再設定を防き、セッションIDの固定化が可能です。サーバ側の防御方法セッションアダプション脆弱性を無くすのが第一です。Esser氏が作成したパッチを多少修正して公開しています。http://wiki.ohgaki.net/index.php?PHP%2Fpatch%2FStrictSessionこのパッチだけでは実際に攻撃された時、ログインできなくなる、などの問題が発生します。次の「アプリの防御方法」の対策も必要です。パッチを適用するだけで、攻撃パスを無効化できます。成りすましは防げるようになりますが、DoSの可能性が新たに生まれます。詳しくは次の「アプリの防御方法」を参照してくだい。アプリの防御方法セッションアダプションに脆弱なセッションモジュールでは完全な対策は取れません。セッションアダプションに脆弱なセッションモジュールを使っていても防御効果は期待できます。jp(TLDですが念のため)に設定されているかも知れないセッションID用のクッキーを削除します。(過去の有効期限の空クッキーを送る)ログイン時には必ず上位ドメインのセッション管理用のクッキーをクリアした上で、新しいセッションIDを発行するようにします。これで多くの攻撃を防げます。これでかなり安全になるのですが、このようなクッキー削除を行っているアプリケーションはほとんどありません。上位ドメインのクッキー削除を怠ると、パッチ済みのPHPではセッションIDの更新ができなくなります。初期化済みのIDを用意しても、ブラウザが繰り返し未初期化のIDを送信するからです。上位ドメインのクッキーを削除しないとDoS状態になってしまう事があります。パッチの有無に関わらず、上位ドメインのクッキーを削除すべきです。セッションID管理用のクッキー名を変更するのも気休めにはなります。セッション管理用のクッキー名は公開情報なので、この対策は本気の攻撃者には無意味ですが、特定の攻撃目標を設定していない攻撃者には有効な防御策です。アプリケーションがどれくらいPHPのセッションアダプション脆弱性に対して弱いのか調べるのは簡単です。ログイン時に実行すべきセッションIDを再生成するsession_regenerate_id()、上位ドメインのセッションIDクッキーを削除するsetcookie()が実行されているかどうか調べるだけです。強固なセキュリティが要求されるWebmailシステムですが、PHPベースのWebmailシステムで最も広く利用されていると思われる2つのシステム、SquirrelMailとRoundCubeをチェックしてみました。2つともsession_regenerate_id()さえ呼び出していません。形式のURLを持っています。Webmail自体、XSS脆弱性が度々発見されています。仮にWebmailにXSS脆弱性がなくても、サイトのどこかにXSS脆弱性が1つ有るだけで、セッションアダプション脆弱性を悪用するために有効期限の長いセッションIDを設定され、長期間ユーザに知られる事無くセッションが盗まれる(成りすまされる)リスクが非常に高いです。通常、XSS脆弱性だけではログインしている場合のセッションIDしか盗めません。セッションアダプションに脆弱なセッション管理の場合、永続的にセッションを盗む事を可能にします。定期的にクッキーを全部削除したり、保存されているクッキーを確認する方法が有効ですがあまり現実的ではありません。クッキーがどのように処理されるかはブラウザとフレームワークによって異なります。参考までにどのブラウザが比較的安全か調べてみました。アクセスして動作を調べてみました。詳しく各ブラウザの動作を調べていないので、もし古いOperaの様にIPアドレスが引けないドメインに対してクッキーを設定しない動作をしているのであれば、実際の動作と異なる事になります。(co.jpなどは普通IPアドレスが設定されていない)しかし、スピア型の攻撃は可能なので参考にはなると思います。クッキーが設定されない。クッキーが優先される。クッキーが優先される。クッキーが優先されるこのテスト結果からは、SafariとFirefox2の動作が極めて悪い動作であることが分かります。これらの動作は、クッキーの設定順序なども動作に影響しているかも知れません。次の「クッキーの実装がいい加減な理由」を見て頂ければ分かりますが、どのように動作するのかはブラウザの実装が関係しています。実際のWebアプリケーションがどのように振る舞うかは、Webアプリケーションが利用しているフレームワークの実装に影響されます。PHPの場合はPHP本体がクッキーのデコードを行い配列($_COOKIE)に保存するので、フレームワークによって動作が変わることはありません。他の言語の場合、クッキーのデコードはフレームワークが行うので同じ言語でもフレームワークが異なると動作が異なるでしょう。Operaを利用している方がより安全であることが分かります。現在のクッキーの実装はNetscapeのクッキー仕様となっています。手抜きで調べていないので、間違っていたら指摘していただきたいのですが、たしかNetscapeの仕様では複数のクッキーが設定されている場合、どういった順序で送信するのか決まっていません。パス、ドメインなどで複数のクッキーを設定することは簡単です。以下はFirefox3でcookie.phpにアクセスした時のHTTPリクエストヘッダです。var=example.co.jp複数クッキーが設定されている場合、どのような条件で設定されたか判別する情報なしに列挙されている事がわかります。他のブラウザでは試していませんががFirefox3ではcookie.phpのクッキー設定順序を反対にして試してみました。クッキーの設定順序に関係なく、この順番に送信されるようです。Firefox3の場合、優先順位が高いと思われるクッキーが先に書かれていると思われます。PHPでは最初に現れたクッキーが優先されるので、PHP+Firefox3の組み合わせは比較的安全に利用できることが分かります。繰り返しになりますが、Firefox3であれば全てのフレームワークが比較的安全に利用できるとは仮定できません。フレームワークのクッキー初期化の仕様によります。他の言語のフレームワークでの動作も調べたかったのですが、手抜きで調べていません。調べた方がいらっしゃる場合は是非教えてください。まとめ個人的にはこの脆弱性は既知のPHPの脆弱性の中では、影響範囲、攻撃の難易度、攻撃された場合の検出可能性などを総合的に評価して、最悪の脆弱性だと思っています。パッチは何年も前から公開されています。セッションアダプションを修正したパッチを適用したPHPビルドを採用しているディストリビューションは見たことがありません。(過去のMomongaLinuxを除く。今のMomongaLinuxにはパッチは当ててありません...)PHPセキュリティレスポンスチームに連絡しても、残念ながら無駄な努力に終わるので、利用されているディストリビューションに問題を報告して、パッチを適用するようにお願いするのが脆弱性対策のもっとも近道だと思います。パッチを適用していても、アプリケーション側で上位ドメインのクッキーを削除するコードを追加する対策も必ず行う必要があります。これを怠ると、上位ドメインにクッキーを設定するだけでDoSが可能になります。この脆弱性を利用すると、セッションアダプションに脆弱なサイトに対して非常に簡単に成りすましが可能になります。出来心で他人に成りすまし、人生を棒に振らないようにしてください。今すぐできる、Webサイトへの2要素認証導入PHPのOpenSSL関数を利用して暗号化する例そもそもエスケープとは何なのか?知らないと勘違いする「合成の誤謬」の罠2要素認証のTOTPとHOTP、どちらがより安全か?紹介エレクトロニック・サービス・イニシアチブのWebシステムのコンサルタントのブログです。PHPの開発、PHP4.x/5.xレガシーPHPセキュリティパッチサービスなどを行っています。ブログのサブタイトルを「書かない日記」としているのは、ブログを始めた時にあまり書かないつもりで始めたのでこのサブタイトルになっています。yohgaki@ohgaki.net私が記述したブログ中のコードは記載が無い場合はMITライセンスです。その他のコードは参考リンクなどのライセンス情報を参照ください。