徳丸さんがセッションアダプションをなくしても、セッションハイジャックが出来るのでsession_regenerate_id(true) (trueを付けると古いセッションデータは削除される)をしなければならないという記事を書かれています。
セッションアダプションがなくてもセッションフィクセイション攻撃は可能
http://tumblr.tokumaru.org/post/37676352092/session-adoption-and-session-fixation
まず結論を書きます。徳丸さんが「セッションフィクセイション攻撃は可能」と言われているのは間違いです。正しくは「セッションハイジャックが可能」です。
この議論は別々の異なる脆弱性を一緒にした議論で正しい議論とは言えません。セッションアダプション、セッションフィクセイション、セッションハイジャックとはどのような脆弱性なのか整理して議論する必要があります。
セッションアダプション
未初期化のセッションIDを正規のセッションIDとして受け入れてしまうセッション管理機構の脆弱性
セッションフィクセイション
セッションIDの固定化が可能な状態を利用して、本来未知であるべきセッションIDを既知のセッションIDに固定化してしまう脆弱性
セッションハイジャック
ユーザが現在利用しているセッションIDを何らかの手法(盗聴、Javascriptインジェクション、セッションフィクセイションなど脆弱性)によって盗み取る攻撃
セッションアダプション、セッションフィクセイション、セッションハイジャックと書くのは長いので以下はアダプション、フィクセイション、ハイジャックとして説明します。
アダプションとフィクセイションとハイジャックの関係
アダプション脆弱性はフィクセイションを行える脆弱性の一種です。できの悪いセッション管理機構ではアダプション脆弱性が無くてもフィクセイションが可能です。実際にあったフィクセイションの例には
$session_id = sha1(‘username’ . ‘password’.’random string’);
と、ユーザ名とパスワードからハッシュ値を取得してセッションIDとして利用していたシステムがありました。本当にできの悪いセッション管理機構ではsaltとなる’random string’さえ無いハッシュ値をセッションIDにしていました。saltさえ無い場合、比較的簡単にハッシュ値からブルートフォース攻撃でパスワードさえクラックできてしまいます。
このようなセッション管理ではセッションIDは常に同じIDになってしまいます。「IDが固定化」されるのでフィクセイション(固定化)と呼ばれています。
アダプション脆弱性を利用した攻撃はフィクセイション脆弱性を利用した攻撃の一種です。さきほど説明したフィクセイション脆弱性はセッションIDの生成が固定化してしまう実装ですが、アダプション脆弱性があると任意のセッションIDに固定化できてしまう場合があります。アダプションを利用したフィクセイション攻撃です。
ハイジャックとはセッションIDを何らかの手法を用いて盗む攻撃です。ハイジャックはセッション管理機構の脆弱性に関係なく実行できる攻撃です。セッション管理機構にフィクセイション脆弱性がある場合はより簡単に実行できる攻撃です。セッションIDを盗むには、盗聴、フィクセイション、Javascriptなどにより盗む、ページやURIなどに含まれているセッションIDを盗む、などの手法を用います。
徳丸さんもセキュリティスペシャリストの一人なので上記の事は理解していて
上記のセッションフィクセイションの攻撃シナリオでは、セッションアダプションは使っていません。その代わりに、攻撃者は、攻撃対象サイトに先にアクセスして、「有効なセッションID」を取得し、それを被害者のブラウザにセットしています。元々が、攻撃対象サイトが発行したセッションIDなので、PHPはそのまま当然のように受け入れます。
「アダプションは使っていません」と書いています。
徳丸さんの攻撃パターンは、「これはXSS攻撃用の罠のURLを生成しているのです。」と書いてあるとおりJavascriptインジェクションを利用して攻撃者に既知である有効なセッションIDを作っています。これはそもそも私も解説している攻撃パターンと全く同じです。(違いはガーベッジコレクションされているか、いないかだけです)
有効なセッションIDであれば受け入れるのは当然です。仮にhttponly属性でJavascriptからクッキーを保護していても、Javascriptインジェクションに脆弱性である時点でそのアプリケーションの情報は盗めてしまいます。セッションは盗めなくてもDOMでページコンテンツを盗めば良いだけです。
では、どのような場合にアダプション脆弱性を無くしたセッション管理機構はより安全になるのでしょうか?それはアダプション脆弱性の定義を見れば分かります。アダプションは「未初期化のセッションIDを正規のセッションIDとして受け入れてしまうセッション管理機構の脆弱性」です。セッションIDが未初期化である場合にセッションIDが保護されます。
app1.example.comやapp2.example.comとドメインによってアプリケーションやユーザ(ホスティングなど)を分けている場合、www.example.com/app1やwww.example.com/app2とパスによってアプリケーションやユーザを分けている場合に有効です。このようなアプリケーションやユーザの分割はよくある構成です。
このような構成にし、アプリケーション(またはユーザ)を分割しているとします。ここではapp1とapp2が別のセッションセーブパス(session.save_path)を持っているとします。同じサーバでユーザやアプリケーションを分割する場合、session.save_pathも分割するのがベストプラクティスなので覚えておきましょう。session.save_pathで指定するのはセッションデータのデータベースとなる場所(DBやファイル)です。ユーザが両方のアプリケーションを利用している場合でも、セッションセーブパスが異なればセッションIDが同じでも、app1とapp2で利用されるセッションデータベースは異なります。Javascriptインジェクションなどを使いapp1からapp2で使うセッションIDを指定しても、app2のセッションデータベースでは未初期化です。アダプション脆弱なセッション管理機構の場合、未初期化のセッションIDを受け入れてしまいますが、脆弱性がないセッション管理機構の場合は新しいIDが生成されapp2は守られます。
ドメインやパスでアプリケーションやユーザを分割する構成はよく見かける構成です。アダプション脆弱性が無いセッション管理機構を用いベストプラクティス通りにセッションデータベースを分割していれば、仮にプログラマのミスや一見判別しづらいコード実行パスを変更できてしまう脆弱性がありsession_regenerate_idを呼び出さない問題があっても、他のユーザやアプリケーションの脆弱性の影響を受けなくなります。
システム管理用のアプリケーションには、システム管理者や開発者のみが使うことを前提にセキュリティが甘いアプリケーションが多い傾向にあります。パスやドメインで分割されている方も多いでしょう。同じサーバにインストールしている方は、これを機会にsession.save_pathの設定を再確認してみると良いかも知れません。
まとめ
徳丸さんは「セッションアダプションをなくしても、セッションフィクセイション攻撃は可能」としていますが同じセッションデータベースを共有しているシステムなのでアダプションと呼ぶのは間違いです。ハイジャックの一種、と分類すべきです。
セッションIDはWebセキュリティの要なので、プログラムの不具合によって盗めてしまう脆弱性は極力排除すべきである、とすることに異論がある方は居ないでしょう。徳丸さんの例からも分かるようにベストプラクティスと呼ばれるコーディングや構成に従う事は非常に重要です。私もsession_regenerate_idでイベント毎、定期的にセッションIDを更新することをベストプラクティスとしてお勧めしています。Webシステムの仕様上の問題で直せない問題などもありますが、直せる脆弱性は全て直す、これもベストプラクティスです。致命的な問題の攻撃パスと成り得る脆弱性が直せるのに直さないで大丈夫です、という開発者が作っているソフトウェアを使いたい、と思う方は少ないはずです。
ところで私が考えるSQLインジェクションを防ぐ為にプログラマに教えるべきベストプラクティスは徳丸さんとは異なります。これも、そのうちまた議論したいと思います。プレイスホルダにとらわれ過ぎていて、フォーマット文字列をプレイスホルダと同じだと勘違い(?)したケースは私も興味深かったです。
セッション管理のベストプラクティスもまとめておいた方が良さそうです。これはオライリーさんのPHPセキュリティ本の中でまとめることにしています。
徳丸さんのブログもあまり読まずに、サクッと書いたエントリなので何か勘違いしていたり、間違っている事があるかも知れません。もし気になったらツイッターやフェースブック、コメントなどで教えてください。
関連エントリ
補足
セッションデータベースが同じでも、期限切れで削除されている場合はアダプション脆弱性が無いセッション管理機構なら保護されます。このアダプション脆弱性を利用して攻撃する場合、有効期限が長いセッションIDクッキーを利用して攻撃すると考えられるます。session_regenerate_idを呼ばない脆弱なアプリがあり、データベースが同じ場合でも保護できる場合もあるということです。セッションの有効期限を短くする事はベストプラクティスです。セッションクッキーを使ったり、セッションIDをイベント毎や定期的に変更したり、ガーベッジコレクションを短めに設定する(セッションIDを定期的に変更するタイミングに合わせる)、などがベストプラクティスです。
補足2
徳丸さんの記事よく読まないで書いている、と最初にエントリを書いたときに書きましたが。エントリのタイトル名をよく読んでいませんでした。セッションアダプションとセッションハイジャックを間違えてタイトルに書いているとは思っていなかったので勘違いして書いていました。「セッションアダプションをなくしても、セッションフィクセイション攻撃は可能」これは明らかな間違いなので本文の一部を修正しました。(私はPHPで問題が議論され始めた古い定義のフィクセイション、徳丸さんは今CWEなどで定義されているフィクセイションで話をしていたので、明らかな間違いと呼ぶも間違いと言えます。この部分は訂正します。)
補足3
直そうとしている脆弱性がどのような脆弱性なのか分類不足であるために、議論が咬み合わないようです。セッションID管理の問題は固定セッションID、不正セッションIDを受け入れるアダプション、セッションIDをインジェクションするフィクセイション、などに分類して考える方が解りやすいでしょう。これは別エントリで整理したいと思います。