こんにちは、AIシステムズです。
この記事は、代表コバが現場で対応してきたPHP・Webアプリ運用の知見をもとに、AIを活用して構成・執筆し、弊社にて最終チェックを行ったものです。
「ログインしたのに次のページで未ログイン扱いになる」「ショッピングカートの中身が突然消える」「ロードバランサ配下でセッションが維持されない」——PHPベースの業務システムやECサイトで頻発するトラブルです。セッションが維持されない原因は、Cookie・保存先・ロードバランサ・タイムアウトの4層に分けて考えると整理できます。
- PHPセッションが切れる主要原因
- セッションCookieとSameSite属性
- セッションの保存先(ファイル・Redis・DB)
- ロードバランサ配下での落とし穴
- セキュリティ上やってはいけない設定
目次
- セッションが切れる典型パターン
- Cookieの設定を見直す
- セッション保存先の選定
- ロードバランサ配下での対応
- こういうサイトに向いている/向いていない
- 再発防止チェックリスト
セッションが切れる典型パターン
弊社が中小企業のPHPアプリで対応してきた中で、原因は次のいずれかです。
- セッションCookieのSameSite/Secure設定が今のブラウザ仕様に合っていない
- セッションのGC(gc_maxlifetime)が短く、すぐ消える
- ロードバランサ配下で複数のPHPサーバーがあり、それぞれが別の場所にセッションを保存している
- セッション保存先のディスクが満杯、または
session.save_pathに書き込めない - サブドメイン・httpとhttpsの混在で、Cookieが別ドメイン扱いされている
Cookieの設定を見直す
SameSite属性
2020年以降のChromeでは、SameSite未指定のCookieはデフォルトで Lax 扱いになりました。クロスサイトの遷移(外部決済からの戻り、SAML認証からのリダイレクト)でセッションが切れる原因はこれであることが多いです。
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '.example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax', // クロスサイトが必要なら'None'+secure
]);
session_start();
SameSite=None を使う場合は、必ずSecure属性とセットで指定します。Secureなしの None はブラウザに拒否されます。
ドメイン指定
サブドメイン間でセッションを共有するなら、domain を .example.com のようにドット始まりで指定します。www.example.com 限定にすると、app.example.com へ遷移した時点でセッションが切れます。
セッション保存先の選定
- files(デフォルト):単一サーバー構成なら問題なし。複数台で動かすと共有できない
- Redis:複数台構成での標準。高速・スケーラブル
- DB(MySQL等):既存DBインフラに乗せたい場合。Redisより遅いが運用が単純
Redisへの切り替え例:
// php.ini または ini_set
session.save_handler = redis
session.save_path = "tcp://redis-host:6379?database=0"
ロードバランサ配下での対応
複数のPHPサーバーが裏にいる構成では、セッションを必ず外部ストア(Redis等)に集約します。これをやらずに「スティッキーセッション(同じユーザーは同じサーバーに振り分け)」で逃げる構成は、サーバー1台が落ちたときにそのサーバーに紐付くユーザー全員のセッションが切れます。
さらに、ロードバランサ配下でHTTPS終端している場合、PHP側で$_SERVER['HTTPS']が空になります。secure属性のCookieを発行するには、次のような判定が必要です。
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
セッションの寿命設定
セッションの寿命は2種類あります。
session.gc_maxlifetime:サーバー側でセッションデータを保持する秒数session.cookie_lifetime:ブラウザ側でCookieを保持する秒数
両方を一致させないと、片方だけ生きていてもログインが続かない状態になります。たとえばカートの保持を24時間にしたいなら、両方を 86400 に設定します。
こういうサイトに向いている/向いていない
このセッション整備は、ログイン機能・カート・予約フォームを持つ中小企業のPHPベース業務システム・ECサイトに直接効きます。完全に静的な情報サイトには無関係です。
再発防止チェックリスト
- SameSite属性を明示的に指定しているか
- HTTPSサイトでSecure属性を付与しているか
- 複数台構成なら外部セッションストアに集約しているか
- セッションのgc_maxlifetime と cookie_lifetime が一致しているか
- セッション保存先ディレクトリのディスク容量を監視しているか
まとめ
PHPセッションが切れる原因は、Cookie属性・保存先・ロードバランサ判定・寿命設定の4層に切り分けて対応します。SameSite明示、外部ストア化、X-Forwarded-Proto判定の3点を押さえれば、ほとんどのケースで安定します。
本記事は、代表コバが中小企業のPHPアプリ運用の現場で対応してきた知見をもとに、AIを活用して構成・執筆し、弊社にて最終確認を行っています。認証システムの設計、複数台構成への移行、セッション周りの問題切り分けについて、具体的な状況をふまえた相談を承っています。費用感だけ知りたい方も、お気軽にご相談ください。