なぜPHPアプリにセキュリティホールが多いのか?

第25回 PHPのアキレス腱 ── セッション管理

この記事を読むのに必要な時間:およそ 5 分

PHPのセッションモジュールの仕様

PHPのセッションモジュールは同じセッションID名(デフォルトはPHPSESSID)を持つクッキーが複数送信されてきた場合,最初のクッキーを優先して利用します。つまり,後に続くクッキーは無視されます。

PHP以外のセッション管理機構では,最後に設定されたクッキーが優先されるものもあります。

ブラウザの仕様

さらに話を複雑にするのはブラウザの仕様です。Webアプリケーションセキュリティの要といえるクッキーですが,実は明確な仕様が決まっていません。にわかには信じ難いと思う方もいるかも知れませんが,本当に明確な仕様が無いのです。

現在ブラウザに実装されているクッキーは,Netscape社のNetscapeブラウザのクッキー仕様と実装をベースにしています。Netscape社はクッキーの仕様を公開していましたが,この仕様は非常にいい加減で,複数のクッキーが設定されている場合,どのように取り扱うか決まっていません。

その結果,ブラウザによって複数のクッキーが設定されている場合にどのような順序で送信するのかばらばらになっています。

クッキーを設定する場合,ドメインとパス属性を使ってクッキーを設定できますが,どのクッキーがどのような条件で設定されたクッキーであるのかもまったく分からないようになっています。

クッキーベースのセッション管理の攻撃

クッキーベースのセッション管理機構のセッションアダプションの攻撃方法には,ドメインを利用する方法,パスを利用する方法,クッキーファイルを利用する方法の3種類があります。

ドメインを利用する方法

PHPのセッションモジュールは,デフォルトではURLのホスト名部分のすべての文字列を利用してセッションID用クッキーを設定します。

ブラウザによっては親ドメインに設定されたクッキーを最初に送信します。親ドメインにセッションID用クッキーが設定されていると,PHPのセッションモジュールは完全ホスト名ではなく,親ドメインのクッキーを優先します。

例えば,筆者の個人ドメインであるohgaki.netでは

  • www.ohgaki.net
  • wiki.ohgaki.net
  • blog.ohgaki.net

の3つのDNS名で運用しています。もし,www.ohgaki.netのアプリケーションにJavaScriptインジェクション脆弱性があった場合,JavaScriptを利用してohgaki.netドメインのPHPのデフォルトセッション名であるPHPSESSIDクッキーに特定の値を設定可能です。

筆者が親ドメインのクッキーを先に送信してしまうブラウザを使いながら,www.ohgaki.netのJavaScriptインジェクション脆弱性によって攻撃されると,セッションの固定化攻撃に成功する可能性があります。wiki.ohgaki.net以外のwww.ohgaki.netとblog.ohgaki.netで利用しているブログアプリがsession_regenerate_id関数を呼んでセッションIDを再生成していても,ohgaki.netに設定されたクッキーが優先されてしまうため,新しいセッションIDは利用されず,攻撃者にとって既知のセッションIDでセッションを初期化してしまうからです。

対策がとられていない場合,ユーザは攻撃されていることにまったく気づきません。攻撃者が設定したセッションIDでセッションを初期化しログインすると,セッションの乗っ取りが可能になります。

パスを利用する方法

まず最初にセッションモジュールがどのようにクッキーのパスパラメータを設定しているか説明します。セッション開始時やsession_regenerate_id関数が設定するセッションID用クッキーのパスはphp.ini設定により決まります。この設定は,session_set_cookie_params関数で変更することも可能です。デフォルト設定のパスは⁠/⁠に設定されています。

複数のアプリケーションを同じドメイン名(DNS名)で運用している場合も多いと思います。例えば,

  • http://www.ohgaki.net/blog なら ブログ
  • http://www.ohgaki.net/wiki なら Wiki

などのようにパスでアプリケーションを別けているサイトも多いと思います。

どのパスのクッキーを最初に送ってくるかはブラウザ次第ですが,深いパスのクッキーを最初に送信するブラウザがほとんどです。つまり,もし

  • http://www.ohgaki.net/wiki/

のアプリケーションにJavaScriptインジェクション脆弱性があった場合,Wikiアプリケーションの安全性が脅かされるだけでなく

  • http://www.ohgaki.net/blog/

で運用しているアプリケーションの安全性も損なわれます。

それはブラウザが⁠/wiki/⁠パスはもちろん,⁠/blog/⁠パスにもクッキーを設定することを許しているからです。ブラウザはパスが実在しようとしまいと関係なしに,パス設定付きのクッキーを許しています。

既に説明した通り,ほとんどのブラウザは深いレベルのパスのクッキーを最初に送信します。つまり,デフォルトのセッションの初期化やsession_regenerate_id関数は⁠/⁠にクッキー設定をするので,攻撃者が設定した攻撃用のセッションIDを上書きすることができません。

session_regenerate_idのdelete_old_sessionオプション

session_regenerate_id関数はオプションで,セッションデータを削除してから新しいセッションIDを設定するように動作させることができます。

session_regenerate_id(ture);

と呼び出すと,新しいセッションIDを設定する前にsession_destory関数を呼び出します。しかし,この動作は,PHPの内部でセッションデータを破棄するだけなので,セッションアダプション脆弱性を利用した攻撃に何の意味もありません。

クッキーファイルを利用する方法

この方法がセッションアダプションに脆弱なアプリケーションに対して最も強力です。多くのブラウザはサーバが送信してきたクッキーをファイルに保存しています。このファイルに直接アクセスでき,読み取り専用にできればクッキーの値は変更できなくなります。つまり,サーバ側でいかなる手段をとっても,読み取り専用のクッキーファイルを利用して攻撃された場合は防御の方法がありません。

著者プロフィール

大垣靖男(おおがきやすお)

University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て,エレクトロニック・サービス・イニシアチブ有限会社を設立。
オープンソース製品は比較的古くから利用し,Linuxは0.9xのころから利用している。オープンソースシステム開発への参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトでは,PostgreSQLモジュールのメンテナンスを担当している。

URLhttp://blog.ohgaki.net/

著書