PHP Advent Calender用のエントリです。
PHPのセッション管理は非常に簡単です。セッションをsession_start()で開始して$_SESSION配列を使うだけです。便利で簡単なセッションモジュールですがセッションアダプションに脆弱であるため、一般に言われてる「ログインする時にはsession_regenerate_id()を呼ぶ」コーディングではセッションアダプションに脆弱になってしまいます。
まずは危険性と対策を紹介します。
セッションアダプションの危険性
セッションアダプションとは外部などから設定されたセッションIDを受け入れ初期化する脆弱性です。一番分かりやすい例はTrans SIDを有効にして
http://example.com/index.php?PHPSESSID=1234567890
とアクセスするとセッションIDが”1234567890”として初期化されます。他のページからのリンクでも初期化される(php.iniでRefererを設定して制限も可能)ので、本来秘密であるべきセッションIDを攻撃者が知ることになります。Trans SIDを利用している場合、session_regenerate_id()を呼べば確実に新しいセッションIDが設定されるのでセッションアダプションによってセッションIDの固定化が起こる事はありません。
セッション管理にクッキーを利用している場合は違います。例えば、アプリケーションapp1がhttp://example.com/app1/ にインストールされていてセッション管理用のクッキーのパスが/app1/に設定されている場合、何らかの方法で/にセッション管理用のクッキーを設定すると、/app1/ではなく/に設定されたクッキーが有効になります。session_regenerate_id()でパス /app1/ に対して何度新しいクッキーを設定しようとしても/に設定されたクッキーが送信されます。
PHPのデフォルトはdomainに対してクッキーを設定しませんが、domainに対してクッキーを設定するとそちらを優先してしまうブラウザ(IE)があります。例えば、www.example.co.jpの場合、何らかの方法でwww.example.co.jp、example.co.jp、co.jpなどにセッション管理用のクッキーを設定できればそれが優先されてしまいます。
co.jpにはクッキーは設定できないのでは?と思った方も居るでしょう。しかし、IPアドレスが返ってくればco.jpにもクッキーが設定できてしまいます。この仕様を利用すれば同僚のブラウザのセッションを簡単に盗む事ができます。PCのhostファイルを編集し、co.jpにIPアドレスを割り当てた上でグラウザに攻撃用のクッキーを設定するだけです。明示的にクッキーを削除するかクッキーの有効期限が切れるまで憐れな同僚はセッションが漏れた状態になります。
セッションアダプションに脆弱なセッション管理では比較的安全とされているクッキーベースのセッション管理の場合、Webアプリセキュリティの要であるセッションを盗む事が可能となるのです。
対策
session_regenerate_id()だけではセッションアダプション脆弱性を利用したセッションの固定化攻撃を防ぐ事はできません。既に対策にはついてはブログに書いているのでこちらを参照してください。
http://blog.ohgaki.net/how-to-make-php-session-strict-by-php-script
セッションアダプション克服への道のり
セッションアダプション対策はまだリリースされているPHPには取り込まれていませんが、もうすぐsubversionレポジトリにコミットする事ができます。
パッチ: https://gist.github.com/1379668
WikiのRFC: https://wiki.php.net/rfc/strict_sessions
セッションアダプション対策への道のりは非常に長いものでした。その概略を紹介します。
2005年夏
- Stefan Esser氏がPHP 5.1用にStrict SessionパッチをMLに投稿。
- ちょうどPHP 5.1.0のリリース前だったので取り込まれると思っていた。
- MLのスレッドは全ては見ていなかったので推測ですが、セッションアダプション脆弱性とブラウザの仕様が理解されていなかったのだと思われる。
セッションアダプションが致命的な脆弱性であることは今も昔も変わりません。6年以上前の事になりますがセッションアダプションは当時でも危険と認識されている問題でした。(少なくともセキュリティ専門家には)
2005年秋
- Stefan氏のパッチの一部が取り込まれる。(後に役に立たない実装だと判明)
- 対策済みと考えていた為「Webアプリセキュリティ対策入門」にもユーザスクリプトによる対策は記載しない。。。
コミットログの差分を斜め読みしていたため、完全にパッチが取り込まれたと勘違いしていました。
2006年春
- Stefan氏のパッチが完全に取り込まれておらず、役に立たない実装だと気づく。
- PHPのsecurity用のメールにStefan氏のパッチが取り込まれていない事に対して適用すべきとメールを送るが、開発者の理解をえられず適用されない。
2006年11月
- PHP 5.2.0リリース。依然としてパッチは取り込まれない。
2007年初め頃(?)
- PHP 5.2用にパッチが無いのは困るので5.2にポート。
- 桝形さんがPHP4用にパッチをバックポート。
- http://wiki.ohgaki.net/index.php?PHP%2Fpatch%2FStrictSession
2007年夏
- PHPプロジェクトメンバーのセキュリティ認識に辟易していたStefan Esser氏がMonth of PHP Bugsプロジェクトを開始。
- 私は日本語に翻訳。 http://blog.ohgaki.net/MoPB/
2008〜2009年頃
- PHP 4のメンテナンス終了のアナウンス。
- そろそろセッションアダプション脆弱性への理解も深まったかと思い、securityのメールアドレスへ厳格なセッション管理をするようにメール。
- しかし、理解を得られず。。。
2011年秋
- PHP 5.4.0のリリースに合わせ厳格なセッション管理を行わない事はセキュリティ問題だとPHP開発者のMLに送信する。
- 遂にセッションアダプションの致命性が理解されたのか、今までと違い必要ない、無用である、現状の機能で十分、ユーザが悪い、とする反論は一切なし。
- 現在、パッチは議論中のステータスで反論もない状態で年内中にはtrunkにコミット、PHP 5.4.1とPHP 5.3.10(何時になるかな)には取り込まれる見込み。
セッションアダプションが致命的な脆弱性であることは少しブラウザのクッキーで実験してみれば分かることだと思うのですが、6年を越す歳月が必要でした。
これは酷い!と思った方も居るかも知れませんがこういう事は他のプロジェクトでもよく起きています。商用製品でも10年前から知られていた脆弱性がやっと直った、などと時々ニュースになっている事を記憶されている方も居ると思います。10年かかった訳ではないのでまだ良い方でしょう。
まとめ
- セッションアダプションは致命的な脆弱性
- セッションアダプション対策はユーザスクリプトでも可能
- プログラミング能力が高いプログラマでもセキュリティ脆弱性の評価を適切にできない場合がある
- セキュリティに対して意識が高い開発者の意見は素直に受け入れるべき
PHPプロジェクトがStrict Sessionパッチを素直に受け入れられなかった理由の1つは、一部の開発者が「セッションアダプションなんてたいした脆弱性ではない」と間違った主張を以前からしていた事に原因があるのではないか、と思っています。
「サニタイズで十分」「プリペアードクエリを使えば安全」といった認識と同様、周りの人にこれで十分、と言っていた人はなかなか意見を変えません。それが間違った意見や合理的ではない意見であったとしても変えない事があります。
この様な状況に陥ると正しいセキュリティ対策が採用されるまでに非常に長い時間がかかってしまいます。そうならないよう「あ、こっちの方が良いかも」と思ったら昔の意見は封印するのが最も良いと思います。