備忘録。
── 同一ドメイン配下で複数 PHP アプリケーションを運用する場合の注意点
PHP のバージョンアップや設定整理を行うと、それまで問題なく動作していた処理について、設計上の前提を再確認する必要が生じることがある。
本記事は、PHP 8.4 への移行作業を進める中で、ログイン処理におけるセッション設計を見直すことになったケースの整理である。
扱う内容は PHP 8.4 固有の不具合ではなく、同一ドメイン配下で複数の PHP アプリケーションを運用する構成において一般的に起こり得る設計上の注意点である。
環境
- サーバ:Xserver 共用サーバ
- PHP:8.4
- 構成:
- 複数の PHP アプリケーション
- デモ用ログイン機構を含む独立したスクリプト群
- 同一ドメイン配下で併用
発生していた挙動
デモ用に用意していたパスワード付きログインページにおいて、次のような挙動が確認された。
- 正しいパスワードを入力するとトップページへ遷移する
- 直後に未認証と判定され、再びログインページへ戻される
- この遷移が繰り返され、結果としてページ遷移がループする
この時点で重要なのは、
認証処理自体は通過しているが、
次のリクエストで認証状態が参照できていない
という点である。
認証が維持されなかった理由
認証状態は $_SESSION に保持する実装になっていた。
$_SESSION['authenticated'] = true;
しかし、リダイレクト後のリクエストではこの値が存在せず、毎回「未認証」と判定されていた。
つまり問題は、
セッションが次のリクエストに引き継がれていなかった
ことにある。
なぜセッションが引き継がれなかったのか
原因は単一ではなく、
いくつかの設計上の条件が重なっていた。
セッション名がデフォルトのまま共有されていた
PHP のセッションは、セッション名(デフォルトは PHPSESSID)によって識別される。
本環境では、
- 複数の PHP アプリケーション
- 同一ドメイン配下の別スクリプト
がすべて同じセッション名を共有していた。
この構成では、
- 別の処理でセッションが開始される
- 想定外のタイミングでセッションが上書きされる
- 認証情報が保持されない
といった状態が発生しやすい。
セッション開始・Cookie 設定が分散していた
セッションの開始処理や Cookie 設定が、
複数箇所に分散していた。
この状態では、
- 実行順
- Cookie 属性(SameSite / lifetime / secure)
- HTTPS 判定の差異
によって、
同一のつもりで扱っているセッションが別物として認識される可能性がある。
なぜ PHP 8.4 をきっかけに表面化したのか
本件は PHP 8.4 固有の不具合ではない。
- ini 設定の整理
- PHP バージョンアップによる挙動の明確化
といった作業をきっかけに、
それまで問題として顕在化していなかった設計上の前提が表に出たケースである。
対応内容
対応として、以下の点を整理した。
セッション名を明示的に固定
session_name('DEMO_AUTH_SESSION');
他の PHP アプリケーションとセッションを分離するため、ログイン用途専用のセッション名を明示的に設定した。
セッション開始処理を整理
- セッション開始前に状態を確認
- 必要に応じて既存セッションを終了
- セッション設定と開始処理を一箇所に集約
ログイン成功時にセッション ID を再生成
session_regenerate_id(true);
状態遷移を明確にし、セキュリティ面でも望ましい形にした。
結果
- ログイン後の遷移が安定
- 認証状態がリクエストを跨いで維持される
- ページ遷移のループは解消
学びと教訓
- 同一ドメインで複数アプリケーションを運用する場合、セッション名は分離する
- セッション設定と開始処理は一箇所に集約する
- セッション名は「用途」を示す設計要素として扱う
- PHP の更新は、設計の前提を再確認する良い機会になる
まとめ
- 問題の本質は PHP の不具合ではない
- セッション設計の前提が複雑化していた
- 小さな整理で、大きな安定性向上につながった
同様の構成を取っている場合、一度セッション設計を棚卸ししてみる価値はある。