PHP用のCookieセッションセーブハンドラー

(更新日: 2018/09/30)

JWTが凄い使われ方をしているようなので、可能な限りマシなCookieベースのセッションセーブハンドラーを書きました。

試用方法

としてからブラウザで http://127.0.0.1:8888/example.php にアクセスします。簡単なカウンターが表示されます。

PHP 7.1以上、opensslモジュールが必要です。

使い方

鍵は必須です。php -r ‘echo bin2hex(random_bytes(32));’ などとして安全かつ強力な鍵を作り使ってください。

セキュリティと制限

クライアント側にセッションデータを持たせるメリットはサーバー側のリソースを使わない事です。しかし、デメリットは小さくありません。

  • クライアントに送ったセッションデータは無効化できない。(クライアント側任せなので本気でキープしようと思ったら可能)
  • 無効化できないので、仮にWebアプリで不正利用と思われるアクセスに気付いたとしても、セッションの無効化が出来ない。(マスターキーを変えて全てのセッションデータの無効化は可能)
  • 暗号化していてもオフラインで解析が何時まででも可能。
  • Cookieにはロック機構がない。つまりセッションデータがロックされず、レースコンディションが発生する。(更新が失われる、といった事が発生する)
  • Cookieなのでセッションデータは最大でも4KBまで。この実装の場合は他のクッキーなども考慮し最大2KBまでに制限。

基本的にセキュリティ要求が緩いアプリケーションでの使用のみに留めることをお勧めします。これは他のクライアントサイドにセッションデータを保存する仕組み全般に言えます。

色々問題がある、とは言ってもできる限りマトモな動作になるようにしています。実装しているセキュリティ対策には

  • AES256による暗号化(完全にランダムなIV)
  • HKDFの導出鍵による鍵生成(完全にランダムなsalt)
  • セッション開始時間およびセッション再暗号化時間を利用した鍵生成
  • セッション再暗号化時間タイムスタンプを利用した、古すぎるデータ、新しすぎるデータによる再生攻撃防止
  • 60秒毎の新しい暗号鍵の利用
  • 悪い通信環境などで簡単に発生するクッキー送信失敗への対応
  • 暗号データ/暗号キー/タイムスタンプの改ざんの検出
  • session.gc_maxlifetimeを利用した有効期限管理

といった対策が取られています。

単純にセッションデータを暗号化し、セッション管理使う場合に比べると比較にならないほど安全です。とは言っても、サーバー側でセッションデータを管理する方がより安全な管理が可能になります。

残念なのはデフォルトのPHPのセッションモジュールの機能では、タイムスタンプ管理をしていないので、このCookieベースのセッション管理よりも脆弱な仕様となっている部分があることです。これらを強化することは、このCookieベースのセッション管理のタイムスタンプ管理と似たようなことをすれば可能です。

繰り返しますが、クライアント側にセッションデータを置くセッション管理システムはあまり強いセキュリティが必要ないサービスに使ってください。

Facebook Comments