セッションフィクセイションはアダプション脆弱性修正で防御可能

Security 12月 12, 2012
(Last Updated On: 2018年8月4日)

古いエントリを編集すると議論の流れが分かりづらくなるので、前のエントリをベースに新しいエントリを作って議論します。このエントリではアダプション脆弱性を修正すると、どのようなフィクセイション(ハイジャック)から防御されるのか解説します。安全なセッション管理には適切なユーザスクリプトが欠かせないので、全て防御できるわけではありませんが、有用性は理解頂けると思います。

 

セッションアダプションがなくてもセッションフィクセイション攻撃は可能

http://tumblr.tokumaru.org/post/37676352092/session-adoption-and-session-fixation

この議論は別々の異なる脆弱性を一緒にした議論で正しい議論とは言えません。セッションアダプション、セッションフィクセイション、セッションハイジャックとはどのような脆弱性なのか整理して議論する必要があります。議論を分り易くするため、これらの用語の定義は8年ほど前にPHPプロジェクトでこの問題が議論された時の定義を用います。

その上で、徳丸さんがツイッターで提示されたセッションフィクセイションの攻撃パターン(PDF)はアダプション脆弱性で攻撃できなくなることを解説します。論点を明確にする為、細かい部分の解説は省略しています。攻撃に必要な脆弱性は存在している事が前提です。ディフィニティブな解説では無いことを予めご理解下さい。

セッションアダプション

未初期化のセッションIDを正規のセッションIDとして受け入れてしまうセッション管理機構の脆弱性(現在公式なCWE定義はない。既に定義の必要もない過去の脆弱性(修正されていて当然の脆弱性)ということでしょう。)

セッションフィクセイション

セッションIDの固定化が可能な状態を利用して、本来未知であるべきセッションIDを既知のセッションIDに固定化してしまう脆弱性(公式な定義はCWE384。 この定義の場合、セッションDBが同じであることを前提としています。PHPのセッションアダプション脆弱性が原因となるフィクセイションはカバーしていません。)

セッションハイジャック

ユーザが現在利用しているセッションIDを何らかの手法(盗聴、Javascriptインジェクション、セッションフィクセイションなど脆弱性)によって盗み取る攻撃(CWEに定義なし。有効なセッションIDを盗みとる手法が一般にハイジャックと呼ばれる)

セッションアダプション、セッションフィクセイション、セッションハイジャックと書くのは長いので以下はアダプション、フィクセイション、ハイジャックとして説明します。

アダプションとフィクセイションとハイジャックの関係

アダプション脆弱性はフィクセイションを行える脆弱性の一種です。できの悪いセッション管理機構ではアダプション脆弱性が無くてもフィクセイションが可能です。実際にあったフィクセイションの例には

$session_id = sha1(‘username’ . ‘password’.’random string’);

と、ユーザ名とパスワードからハッシュ値を取得してセッションIDとして利用していたシステムがありました。本当にできの悪いセッション管理機構ではsaltとなる’random string’さえ無いハッシュ値をセッションIDにしていました。saltさえ無い場合、比較的簡単にハッシュ値からブルートフォース攻撃でパスワードさえクラックできてしまいます。このようなセッション管理ではセッションIDは常に同じIDになってしまいます。「IDが固定化」されるのでフィクセイション(固定化)と呼ばれています。

PHPのセッション管理機構のフィクセイションはこれとは異なります。未初期化のセッションIDを受け入れるアダプション脆弱性があるため、容易に削除できないセッションIDクッキーを設定する事により、半永久的に同じセッションIDが有効なIDとして使えてしまうフィクセイションが可能になっています。

徳丸さんの提示された資料のフィクセイションとは異なる部分もありますが、(PHPの問題は現在もある問題ですが)これが過去にフィクセイションと呼ばれていた脆弱性の例です。

ハイジャックとはセッションIDを何らかの手法を用いて盗む攻撃です。ハイジャックはセッション管理機構の脆弱性に関係なく実行できる攻撃です。セッション管理機構にフィクセイション脆弱性がある場合はより簡単に実行できる攻撃です。セッションIDを盗むには、盗聴、フィクセイション、Javascriptなどにより盗む、ページやURIなどに含まれているセッションIDを盗む、などの手法を用います。

 

徳丸さんが提示されたフィクセイションの攻撃パターン

PDFには攻撃パターンとして次のパターンが紹介されています。簡単に攻撃パターンを解説しならがアダプション修正パッチがどのような効果を持っているか解説します。

この攻撃パターンは図の説明にあるようにURLベースのセッションID管理を行っている場合に発生する攻撃バターンです。この図はJavaシステムの例ですが、PHPにもURLベースのセッション管理はあります。

session.use_trans_sid = 1
session.use_only_cookies = 0

でURLベースのセッションIDが使えるようになります。

session.use_cookie = 0

を追加で設定すると、URLベースのみのセッション管理が行えます。(セッションIDクッキーは存在しても無視される)この攻撃パターンはアダプション脆弱性を修正すると、攻撃が難しくなります。メールなどで攻撃URLを送ってもセッションデータが有効期限切れで廃棄されると、攻撃者が設定するセッションIDはセッションデータベースには存在せず、未初期化のIDを排除するアダプション修正パッチによって新しいIDが生成されアプリケーションは保護されます。セッションデータの有効期限切れや詳しい条件については次の解説を参考にしてください。

この攻撃パターンはJavascriptインジェクションが可能な場合に行える攻撃です。徳丸さんがデモシステムで紹介している攻撃パターンがこれになります。この場合、アダプション修正パッチで保護できる場合と保護できない場合がありますが、アダプション修正パッチによりリスクは大幅に低減します。この攻撃パターンはクッキーベースのセッションID管理に有効です。PHPの場合、デフォルト設定でクッキーベースのセッション管理が有効になります。

この図ではセッションIDを管理するデータベースが別サーバとして書かれていますが、これはセッション管理データベースが外部にあってデータベースを共有しているケースを想定してると思われます。セッションデータベースが共有されていればよいだけです。セッションデータベースはPostgreSQLやMemcached、NFS上のファイルシステムでも構いません。

まずは攻撃が成功するケースから解説します。攻撃が成功するには、「攻撃者が有効なセッションID」の生成が可能であり、「アプリがJavascriptインジェクションに脆弱」(+JavascriptからセッションIDクッキーを設定可能。おまけも参照)であり、「ユーザ(PHPプログラマ)がログインセッション作成時にセッションIDを再生成&古いセッションデータを破棄しない」ことが条件になります。これら全ての条件が整う事が、攻撃成功の必須条件です。Javascriptインジェクションが可能な場合、このように面倒な攻撃を行わなくても直接セッションIDを盗むハイジャックが行えるシステムも多いでしょう。

アダプション修正パッチは「攻撃者が有効なセッションID」を作る機会を大幅に低減します。PHPのセッション管理機構はセッションデータに有効期限(gc_maxlifetime)を設定しています。デフォルトでは

session.gc_maxlifetime = 1440

session.gc_maxlifetime = 1440

1440秒=24分に設定されています。攻撃が成功するには、攻撃者が取得した有効なセッションIDのデータがセッションデータベースから削除される前に、脆弱な認証コードによりログインしなければなりません。つまり、セッションデータの有効期限が切れて廃棄されればアダプション修正パッチによりアプリケーションは保護されます。

この手法を使って攻撃する場合、攻撃者は有効期限が長い(2032年までなど)セッションIDクッキーを設定します。アダプション修正パッチなしのPHPの場合、有効期限切れでセッションデータが削除されてしまっていても有効なセッションIDとして、攻撃者が設定したセッションIDクッキーを有効なセッションIDとしていつまででも初期化してしまいます。(クッキーのドメイン、パスを設定して単純には削除できないクッキーが作れる事は既に別エントリで解説しています。関連リンクを参照してください)

有効期限が長い攻撃用のセッションIDが長期間に渡って有効なセッションIDとして利用されてしまう事は大きな脅威であると言えるでしょう。セッションデータが削除さえされれば、アダプション脆弱性パッチを適用していると単純には削除できない有効期限が長いクッキーを用いてセッションIDを盗むことはできなくなります

さらに、アダプション修正パッチを適用し、セッションデータが廃棄された状態になると、脆弱な認証プログラム(多少条件付きですが、通常のコードなら保護される)であっても、攻撃者が設定したセッションIDを用いた認証が行えなくなります。この為、ユーザやシステム管理者はシステムに異常があることを知ることができます

攻撃可能な条件が整っている場合の違いをまとめると以下のようになります。

アダプション修正パッチを適用

  • 脆弱な認証コードを攻撃可能な時間はおよそ30分間(デフォルト設定の場合。GCのタイミングは確立で決まるので長くなる場合もある)
  • 攻撃が行われている事を検出できる

アダプション修正パッチを未適用

  • 脆弱な認証コードを攻撃可能な時間は半永久的
  • 攻撃が行われている事を検出できない

 

この攻撃パターンはドメインベースでアプリケーションやユーザを分割しているシステムに有効な攻撃パターンです。ホスティングシステムなどでは良くある構成です。

この図の場合、DNSキャッシュポイズニングを想定していますが、DNSキャッシュポイズニングなどという面倒な攻撃を行わなくても、ドメインベースでアプリケーション、ユーザを分割しているなら、そのまま別のサブドメインを攻撃すれば良いだけです。

この構成に対する防御策は既に別エントリで解説ずみです。アダプション修正パッチを適用し、セッションデータベースを分割すればこの攻撃パターンからも保護されます。(PHPユーザでfilesセーブハンドラを使っている場合、session.save_pathを分割するだけです)

特定のターゲットをDNSキャッシュポイズニングで攻撃する場合、ターゲットのWebシステムにJavascriptインジェクション脆弱性が無くても攻撃できるパターンになります。通常、DNSの脆弱性はWebシステムが制御できないセキュリティ問題ですが、アダプション修正パッチを当てていれば、前の攻撃パターンとどうようにセッションデータが破棄されると保護されます。攻撃者が半永久的なセッションIDクッキーを設定した場合は攻撃された事も検出できます。

 

まとめ

徳丸さんは「セッションアダプションをなくしても、セッションフィクセイション攻撃は可能」としていますが、徳丸さんがフィクセイションの定義として提示された資料に従っても、多くのケースが保護可能です。そして攻撃可能となるにはJavascriptインジェクション脆弱性も必要です。更に、保護できないケースでも半永久的に攻撃されるのではなく、セッションデータが廃棄されれば、攻撃されている事が分かります。アプリが脆弱性であっても攻撃していることが分かる事は重要です。攻撃の検出は攻撃者にとって重大な脅威です

私も攻撃可能なケースを認識していますが、徳丸さんは「セッションアダプションをなくしても、セッションフィクセイション攻撃は可能」と一部の防御できないケースのみを取り上げてフィクセイションの攻撃は可能と主張されています。正しくは「アダプションをなくすと、(脆弱なアプリであっても)フィクセイション攻撃の多くが防御可能」と評価すべきではないでしょうか?

脆弱なアプリ、ライブラリ、コードがあってもシステムの安全性を出来る限り保つ「フェイルセーフ」はセキュリティ対策の重要な概念の1つであることも忘れてはなりません。しかも、アダプション修正パッチはほぼコスト0(増えるのは取るに足らないCコード実行時間+DBルックアップ)です。通常のアプリであれば互換性問題もありません。

このエントリの解説を読んでも、アダプション修正パッチはPHPにとって重要ではないので、あっても無くてもよい修正であると考えるPHPerの方が多いようならわざわざ時間を使ってパッチをPHPソースにマージする必要はないかも知れません。パッチは必要、と思う方はページ上部のFBの”いいね!”ボタンと押して頂けると、どのくらいのニーズがあるのか参考になるのでよろしければ押してください。

別の作業をしながら、短時間で書いて公開しました。おかしな文章、間違いなどがありましたらご連絡頂けるとありがたいです。

おまけ

攻撃可能なケースもWebサーバがhttponly属性を設定したセッションIDクッキーを先に設定していれば、Javascriptから設定された設定されたクッキーは無視されます。つまりJavascriptインジェクション脆弱性を利用して攻撃が成功するパターンでもhttponlyを設定している場合、先にページを表示するのでセッションを無条件に開始しているアプリなら攻撃できません。手元のChromeの動作はこうなっています。しかし、残念ながら先にJavascriptで設定されると、現時点ではこちらが常に優先される仕様のようです。

徳丸さんが提示された「セッションフィクセイション」が全く無いフレームワークもあります。日本製のPHP用フレームワークのPieceFrameworkです。PieceFrameworkはセッションIDを毎回変える動作をフレームワークとしてサポートしています。興味がある方は是非どうぞ。

おまけ2

徳丸さんはアダプションを脆弱性対策として修正しても、攻撃できるケースがあるので重要な対策ではない、あっても無くても良い、と評価しています。これは徳丸さんの”正しいSQLインジェクション対策”の自己否定です。私は徳丸さんの”正しいSQLインジェクション対策”は”SQL初心者向けSQLインジェクション対策”としては、追加の記載事項が必要ですが、とても有用だと評価しています。しかし、”正しいSQLインジェクション対策”ではエスケープ処理は無用と切り捨てています。識別子のエスケープ、特定のSQLデータベースの機能を使う為(例えば、PostgreSQLの配列型やhstore、JSON型)のエスケープ処理が欠かせません。完全でない対策でも有用(アダプション修正パッチはフェイルセーフとしてとても有用)であることも多く、否定的な評価はしません。しかし、徳丸さんの考え方では”正しいSQLインジェクション対策”は不完全であることは明白なので、正しくないSQLインジェクション対策、であるという事になります。

私がかねてから主張している”正しい出力対策”の基本、1エスケープ、2API利用、3バリデーション、であるとする意見に賛成されつもりでしょうか? プログラマがより安全にSQLを実行できるよう考えを変えられるのであれば大歓迎です。

関連エントリ

投稿者: yohgaki