ZAPAnet総合情報局 > ZAPAブログ2.0 > PHPでセキュアなクッキーとセッション

PHPでセキュアなクッキーとセッション

2020年06月26日 プログラミングTIPS
サーバーをさくらのVPSに移転後、Google ChromeでPHPページを確認したら、警告が出ていました。
A cookie associated with a cross-site resource…SameSite=None` and `Secure`
安全なWebのために、Googleでは2020年2月のChrome 80から、セキュアなクッキーの利用と接続が推奨されるようになっています。
SameSite 値を宣言していない Cookie は SameSite=Lax の Cookie として扱われます。サードパーティ コンテキストで利用できるのは SameSite=None; Secure が設定されている Cookie のみになり、それも安全な接続が使われている場合に限られます。

session.cookie_samesite を設定

Chromeのデベロッパーツールで警告が出ている以上、警告が出ないように修正する必要があります。幸い、PHP7.3からは、php.iniで簡単に設定できるようになっています。昔のPHPには存在しなかった「session.cookie_samesite」のオプションが追加されています。
session.cookie_samesite
設定値は、Lax、Strict、Noneなどを設定します。例えばNoneにするなら、以下のように書き換えて設定します。
session.cookie_samesite = "None"
最初、「session.cookie_samesite = None」としたら、samesiteの値が空でした。「session.cookie_samesite = None」ではなく、「session.cookie_samesite = "None"」です。文字列での設定です。あまりネットに情報が出回っていませんので、ご注意ください。

session.cookie_secure を設定

それから、クッキーもセキュアに設定します。
session.cookie_secure = 1
session.cookie_secureとsession.cookie_samesiteを適切に設定することにより、SSLでセキュアな通信ができるようになるというわけです。

httpとhttpsの混在でハマった話

上記「session.cookie_secure = 1」を設定した後、バーチャルホストの別ドメインサイトでクッキーがうまく動かなくなってハマったことがありました。「今までログインできていたのに、なんでログインできなくなったの?」と。

答えは簡単。「クッキーをセキュアにしたのに、HTTP通信を使っていた」から。

常時SSL化したサイトでHTTPS通信していたときに、session.cookie_secureとsession.cookie_samesiteを設定して完璧に動作することは確認していました。ところが、その設定のままSSL化していないサイトでHTTP通信したら、セッションがおかしくなりました。HTTPはセキュアではないので当然です。php.iniで一括で設定してしまうと、HTTPサイトとHTTPSサイトが混在しているときにおかしなことになります。php.iniで設定する場合は、全てのドメインで常時SSL化してHTTPS通信に切り替えてから設定した方が良いと思います。それまでは、PHPファイルの中で、ini_setやsetcookieなどで指定する必要があります。

おまけ:PHPのセッションが切れる仕組み

PHPのセッションが切れるタイミングが同じではなくて、早い時があって驚きました。php.iniで確認したところ、1440秒経過後に1/1000の確率でガベージコレクションで破棄されるようになっていました。1/1000の確率なのは、チェック回数を減らして負荷を下げるためらしいです。面白いですね。この値をいじることによって、PHPのセッションが切れるタイミングを調整することができます。負荷対策のために1/1000の確率になっているらしいので、指定の秒数経過後に100%の確率でセッションが切れるような設定にするのは良くないのかもしれません。また、ユーザーが少ないとセッションは長持ちし、ユーザーが多いと最短でセッションが切れる可能性が高くなります。もしsession.gc_maxlifetimeを設定していてセッション時間の異なるアプリケーションが混在している場合、一番セッション時間の短いアプリケーションの削除処理がヒットすると、同ディレクトリに保存されている全てのセッション切れのセッションが削除されます。例えば、1440秒と14400秒と144000秒のセッションが合った場合、1440秒のセッション削除処理が走ったときに、1440秒しか経過していない144000秒のセッションまで削除されてしまう可能性があります。そのようなミスを避けるために、セッションを保存するsession.save_pathはアプリケーションごとに分けておいた方が良さそうです。

続きPHPのセッションファイルの保存場所と設定場所