PHPのスクリプトを使ってアダプティブなPHPセッションをアダプティブにしない方法を紹介します。
このブログで紹介していたかどうか覚えていないですが、セッションアダプション対策としてsession_regenerate_id()が導入された時に議論・紹介されているので知っている方も多いと思います。(というより、PHPerの常識ですよね?)
まずはセッションアダプションの原理と対策の復習をしておきます。
- 原理: 未初期化のセッションIDを受け入れる
- 対策: 初期化済みセッションIDのみ受け入れる
session_regenerate_id()は新しいセッションIDを生成して新しいセッションクッキーを作成して、セッションデータを保存するようになっています。session_regenerate_id()を呼んだだけでは、なんらかの方法で複数のセッションクッキーがドメイン・パスに設定されている場合、セッションクッキーが更新できない場合があります。この場合、PHPモジュールは同じセッションクッキーで初期化してしまいます。
ユーザ(スクリプト)側でセッションIDが初期化済みであるかどうか確認する事は簡単です。session_regenerate_id()を呼んだ後に、セッション配列($_SESSION)に何らかの目印を埋め込んでおけば十分です。例えば、こんな感じです。
session_destory();
session_regenerate_id();
$_SESSION[‘vaild_id’] = session_id();
このようにセッションクッキーが新しくなるように設定してセッションを利用する前に
if ($_SESSION[‘valid_id’] !== session_id()) {
die(‘Invalid use of session ID’);
}
などと処理します。簡単ですね。念の為に何故これで大丈夫なのか解説しておきます。
上記の手順でセッションIDを設定し、セッション配列を確認すると、外部からセッションIDが与えられたり(URLリライターの利用など)した場合、セッションが破棄されます。セッションIDが再生成された後、セッション配列にPHPで初期化済みである目印としてセッションIDを保存しています。実際にセッションを利用する際に目印が正しいかチェックすると、アダプティブでない厳格なセッション管理が行えます。
私がWebアプリセキュリティ対策入門を書いていた頃はPHP本体でセッションアダプション対策が行われる(行われた)、と考えていたので本の中では紹介しませんでした。セッションモジュールに最初からsession_regenerate_id関数が無かったので、この様な対策を行っているアプリは無かったですし、ユーザ側の対策では対策に漏れが出る事は火を見るより明らかです。既に提案されていた厳格なセッション管理パッチがPHP本体に採用されるのは当然だ、と思っていました。
ユーザ(スクリプト)側でのセッションアダプション対策は既に紹介した通り比較的簡単です。しかし、簡単であってもユーザ(スクリプト)側での対策には問題もあります。
- ユーザ側での対策なので実装されていない可能性がある
- ユーザ側での対策なので実装したつもりでも正しく実装されてない可能性がある
- 他の環境(Java, Ruby, Python,etc)ではセッションアダプション対策が行われているのでWeb開発経験者でも間違える可能性が高い。
- 初めてPHPでWebアプリ開発を行う場合、間違える可能性は更に高い。
- 対策を行っていないアプリが結構あると推測される。
PHPのセッションモジュールでセッションアダプ対策を実装していた方が簡単なだけでなく確実です。セッションモジュールで対策されていればセッションアダプション対策にsession_regenerate_id()を呼ぶ必要さえありません。
最近のPHPアプリの動向を詳しく調べていないので推測ですが、このエントリで紹介された対策を現在でも行っていないアプリが多数存在すると思われます。
PHP開発者はセッションアダプションの問題はユーザ側の問題である、としていますがセッションモジュールを少し改良するだけでアダプション脆弱性問題を全て解決できます。ユーザ側での対策には限界があるのでプラットフォームで対応すべきだと私は考えています。セッションモジュールの改良に副作用もありません。PHPのセッションモジュールのアダプション脆弱性が修正された場合でも、ここで紹介した対策を実装していても何の問題もありません。(一部のアプリに影響する事は知っていますが、特殊なアプリです。一般的なアプリが犠牲になるより特殊なアプリの方で対策すべきでしょう)
セッションアダプション脆弱性を修正すると、セッションを盗まれるリスクの代わりにDoSのリスクが発生します。しかし、これは私が時々紹介している「全てのドメインとパスに設定されているセッションクッキーを削除する」対策を行えばかなりリスクは軽減できます。特定ユーザに対するDoSのリスクがあるとは言っても、セッションを盗まれるリスクの2択でどちらを選ぶか?迷う人は居ないと思います。
最近のフレームワークを利用して開発している方は多分大丈夫だと思いますが、最近のフレームワークを使って開発している方もそうでない方も、セッションIDの管理がどのような実装になっているか確認すると良いと思います。