2026年11月6日、PHPのセッションの既定値が変わる予定について解説記事を書いていた担当が、その記事の「当サイトの確認欄」を書くために、当サイトのログインのCookieの応答を見た。そのとき、SameSiteという指定が付いていないことに気づいた。設定ファイルには、SameSite=Laxと書いてある。それなのに、応答には付いていなかった。
原因は、設定が2か所にあったことだった。書いた場所と、あとから置き換える部品の2か所だ。先に読まれる側に書いた指定を、後から読まれるCMSの部品が、セッションの設定ごとまとめて置き換えていた。書いた行のうち、SameSiteと、知らないセッション番号を受け入れない設定(strict mode)の2つは、一度も効いていなかった。直しは、その後に読まれる上書き用の設定ファイルに書いた。
11月7日、後から読まれる側に、この2つを書き足した。試験用のサイトでは1回目に書き方を誤り、全ページが同じエラーの画面になって、約1分で控えから戻した。2回目に通り、11時23分50秒に本番へ出した。この記事は、見つけた経緯、直し方、1回壊した理由、別の担当の点検で分かったもう1つの穴、本番で前と後を比べた結果を書く。
読み終えたら、担当サイトで「書いたはずの設定が、応答に出ているか」を応答のヘッダーで確かめる手順が分かるようにしたい。安全のため、当サイトのCMSの名前や版、設定ファイルの場所や行、Cookieの名前、セッションの番号は書かない。書くのは、日付、確かめた項目、設定の名前(PHPの公開文書にあるもの)、手順の順番までだ。
何が見つかったか ── 3行で、そしてきっかけ
3行で言うと
- 当サイトのログインのCookieは、応答にSecureとHttpOnlyだけが付いていて、SameSiteが無かった。設定ファイルには、SameSite=Lax・HttpOnly・Secure・strict modeが書いてあったのに。
- 理由は、設定が2か所にあったことだ。後から読まれるCMSの部品が、セッションの設定をまとめて置き換えていた。だから、書いた行のうちSameSiteとstrict modeは効いていなかった。Cookieの名前も、書いた名前と違うものになっていた。
- 置き換えた後に読まれる、上書き用の設定ファイルに、2つを足し直した。試験用のサイトで1回壊して戻し、2回目に通してから、11月7日の11時23分50秒に本番へ出した。
きっかけは、公開前の解説記事を書いていたこと
見つけたのは、ログインの穴を探していたからではなかった。11月6日に、PHP 8.6でセッションの既定の設定が3つ変わるという内容の解説記事(この記事の時点では公開前)を書いていた担当が、その記事の確認欄を、当サイトに当てはめて書くために、応答を見た。そのとき、当サイトのログインのCookieにSameSiteが無いことに気づいた。
記事のチェック項目を、書く最中に自分のサイトへ当てる。この進め方は、記事のチェック項目を自分のサイトに当てたら、自分のサーバーが対象だった ── Apache 2.4.***を、記事を公開したその日に上げるまでと同じだ。書き終えてから確かめるのではなく、書いている最中に当てると、記事の中の「担当サイトで確かめること」が、自分の手で一度通った項目になる。
先に、この記事で書かないこと
当サイトを動かしているCMSの名前と版、設定ファイルの場所と行番号、Cookieの名前、セッションの番号は、書かない。これらを書くと、攻撃の手がかりになるからだ。以下では、CMSの部品、上書き用の設定ファイル、と呼ぶ。また、「完全に安全になった」とも書かない。直したのは2つで、それで塞がったと言えるのは、この記事で確かめた範囲に限る。
書いたはずの設定が、応答に付いていなかった
応答のヘッダーを見ると、付いていたのは2つだけ
Cookieの属性は、サーバーが返す応答のヘッダー(Set-Cookieという行)に入って、ブラウザへ届く。画面を見ても分からない。応答のヘッダーを取って、1行ずつ読む。
本番のログインページへ要求を送り、返ってきたSet-Cookieを読むと、付いていた属性はSecureとHttpOnlyの2つだけだった。SameSiteは無かった。Secureは「HTTPSの通信でだけ送る」、HttpOnlyは「ブラウザ上のスクリプトから読めなくする」という意味で、どちらも大事な属性だ。ただ、SameSiteが無いと、別のサイトから送られた要求にもCookieが付くかどうかを、サーバー側から指定できていないことになる。
設定ファイルには、4つの指定とCookieの名前があった
設定ファイルを読むと、セッションの項目に、SameSite=Lax・HttpOnly・Secure・use_strict_mode=1と、Cookieの名前が書いてあった。つまり、書いた人は、SameSite(Lax)を付け、strict modeを有効にし、Cookieに名前を付けるつもりだった。
書いてあるのに、応答には出ていない。ここで、設定ファイルを何度読み直しても、原因は分からない。設定ファイルは正しく書いてあったからだ。設定ファイルを読んで効いているかどうかを決めず、実際の応答を見て決める。読み直すより先に、「その設定は、あとで別の何かに上書きされていないか」を疑う。
設定が2か所にあり、後から読まれる側がまとめて置き換えていた
調べると、セッションの設定を決める場所が2か所あった。1つ目は、書いた人が指定を書いた設定ファイル。2つ目は、CMSの部品が持っている、セッションの設定だ。読まれる順番は、1つ目のあとに2つ目が続く。2つ目は、セッションの設定を、まとめて置き換える作りになっていた。
置き換えは、項目を1つずつ上書きするのではなく、セッションの設定の塊ごとだった。だから、1つ目に書いた4つの指定のうち、SameSiteとstrict modeの2つは、置き換えの時点で消えた。HttpOnlyとSecureは、応答に残っていた。置き換えた後の設定にも同じ指定があったのだろう、と読んでいるが、どこから付いたのかは確かめていない。Cookieの名前も、書いた名前と違うものが出ていた。これも、置き換えが起きていた証拠だった。
| 書いた指定 | 本番の応答・挙動 | 効いていたか |
|---|---|---|
| SameSite=Lax | Set-Cookieに無かった | 効いていなかった |
| use_strict_mode=1 | 応答には現れない。偽の番号で確かめると、そのまま受け入れた | 効いていなかった |
| HttpOnly | 付いていた | 応答では効いていた(どこから付いたかは未確認) |
| Secure | 付いていた | 応答では効いていた(どこから付いたかは未確認) |
| Cookieの名前 | 書いた名前と違うものが出ていた | 書いたとおりには効いていなかった |
この表の見方は単純だ。書いた行の数と、応答に出た属性の数が合わないとき、書き漏らしではなく、上書きを疑う。HttpOnlyとSecureが残っていたせいで、「Cookieの設定はちゃんと効いている」と思い込んでいた。付いている属性が2つあると、付いていない属性があることに気づきにくい。
SameSiteとstrict modeは、何を守る設定か
SameSite ── 別のサイトから来た要求に、Cookieを付けるか
SameSiteは、Cookieに付ける属性の1つで、別のサイトから送られた要求に、そのCookieを付けるかどうかを指定する。MDN(Mozillaの開発者向け文書)は、次のように書いている。
"The SameSite attribute lets servers specify whether/when cookies are sent with cross-site requests"
(日本語訳: SameSite属性は、サイトをまたぐ要求に、Cookieを送るかどうか・いつ送るかを、サーバーが指定できるようにする。)
PHPの公式の文書は、session.cookie_samesiteという設定について、指定が空のときの扱いを書いている。
"An empty value means that no SameSite cookie attribute will be set."
(日本語訳: 空の値は、SameSite属性を付けない、という意味だ。)
LaxとStrictの違いも、同じ文書にある。Laxは、別のサイトからの「リンクをたどる移動」(GETの要求)にはCookieを送り、別のサイトからのPOSTには送らない。Strictは、どちらにも送らない。ログインのCookieをLaxにしておくと、別のサイトに仕込まれたフォームからログイン済みの画面へPOSTされる、という形のなりすましに対して、1つ防ぐものが増える。
ただし、SameSiteだけで十分とは言えない。OWASP(Webの安全の啓発団体)の手引きは、こう書いている。
"Treat SameSite as defense in depth against CSRF, not as a replacement for a CSRF token."
(日本語訳: SameSiteは、CSRF(別のサイトから、利用者の知らないうちにログイン済みの操作をさせる攻撃)に対する、何重かの守りのうちの1つとして扱う。CSRF用の使い捨ての符号の代わりにはならない。)
strict mode ── 知らない番号を受け入れない
strict mode(use_strict_mode)は、サーバーが発行していないセッションの番号を、受け入れない設定だ。PHPの公式の文書は、次のように説明している。
"If an uninitialized session ID is sent from the browser, a new session ID is sent to the browser."
(日本語訳: 初期化されていないセッションの番号がブラウザから送られてきたら、新しいセッションの番号をブラウザへ送る。)
同じ文書は、「Applications are protected from session fixation via session adoption with strict mode.」(日本語訳: strict modeで、セッションの引き取りによる、セッション固定から守られる)とも書き、全てのサイトにこの設定を有効にするよう勧めている。有効にすると、外から持ち込まれた偽の番号では、そのままセッションが始まらず、新しい番号が出る。
2つは、別の穴を見ている
| 設定 | 何を守るか | 指定が無いと | 応答で確かめられるか |
|---|---|---|---|
| SameSite(Lax) | 別のサイトから送られる要求に、ログインのCookieが付くこと | ブラウザごとの既定の扱いになる | Set-Cookieの行で確かめられる |
| strict mode | 外から持ち込まれた偽のセッションの番号を、そのまま受け入れること | 知らない番号でも、そのまま受け入れる | 応答には現れない。偽の番号を付けた要求を送って、新しい番号が返るかで確かめる |
この表で大事なのは、右端の列だ。SameSiteは応答の行を見れば分かるが、strict modeは応答の行には出ない。だから、SameSiteが付いていないことは目で見て気づけても、strict modeが効いていないことには、別の確かめ方をしないと気づけない。この違いが、後半の「別の担当の点検」につながる。
直し方 ── 後から読まれる側に、書き直した
変えたのは、2つだけ
直し方は、置き換えが終わった後に読まれる、上書き用の設定ファイルに、SameSite=Laxとstrict mode(use_strict_mode=1)の2つを足し直すことだった。先に読まれる設定ファイルは、触っていない。CMSの部品も、触っていない。ほかのセッションの指定(HttpOnly・Secure・Cookieの名前)にも、触っていない。
後から読まれる側へ書く、というのは、「勝つ側に書く」ということだ。設定が2か所で読まれるなら、最後に読まれる場所の値が、最後に残る。先に読まれる場所に何度書いても、後から置き換えられるなら意味がない。
1回目: 試験用のサイトが、全ページ同じエラーになった
最初に試験用のサイトで試した。設定の名前、session.cookie_samesiteを、そのままの文字で書いた。ところが、設定を書く仕組みは、名前の中の「.」を、階層の区切りとして読む。「session」の下の「cookie_samesite」、という入れ子の値として保存された。PHPが期待する、1つの名前としての設定とは、形が違う。
結果、全ページが同じエラーの画面になった。11時05分25秒から26秒の間に、エラーの記録が4件入った。気づいてすぐ、控えから元の設定ファイルを戻した。壊れていたのは、約1分だった。
2回目: 配列のまま書き足して通った
2回目は、名前に「.」を含む設定を、名前で書くのをやめた。セッションの設定を、いったん配列として読み出し、その配列の中に値を足して、配列ごと書き戻す形にした。設定を書く仕組みが「.」を読まない形にした、ということだ。
試験用のサイトでは、5ページが200で返り、ページの大きさは直す前と同じで、Set-CookieにSameSite=Laxが付き、エラーの記録は0件だった。
| 1回目 | 2回目 | |
|---|---|---|
| 書き方 | 設定の名前を、「.」を含めたまま書いた | 配列を読み出して、値を足し、配列ごと書き戻した |
| 設定を書く仕組みの読み方 | 「.」を階層の区切りとして読み、入れ子の値になった | 入れ子にならず、1つの名前の設定として届いた |
| 試験用のサイトの結果 | 全ページが同じエラーの画面。11時05分25秒〜26秒にエラー4件 | 5ページが200・大きさは前と同じ・SameSite=Laxが付く・エラー0件 |
| 対応 | 約1分で控えから戻した | 本番へ出す候補にした |
1回目の失敗は、本番ではなく試験用のサイトで起きた。ここが大事だ。試験用のサイトがなければ、このエラーは本番の全ページに出ていたかもしれない。書き換える前に控えを取ってあったので、戻せた。
別の担当の点検で、もう1つ分かった
偽のセッションの番号を、本番はそのまま受け入れていた
直した内容は、別の担当に、第三者の目で点検してもらった。そのとき、SameSiteの話とは別に、もう1つ分かったことがある。本番は、ほかの人が用意した偽のセッションの番号を付けた要求を、そのまま受け入れていた。
これは、セッション固定と呼ばれる形の穴の入口だ。OWASPは、セッション固定を次のように説明している。
"When authenticating a user, it doesn't assign a new session ID, making it possible to use an existent session ID."
(日本語訳: 利用者を認証するとき、新しいセッションの番号を割り当てないので、すでにある番号を使えてしまう。)
前節の表のとおり、strict modeが効いていなかったことが、この穴の入口になっていた。strict modeを足し直すと、知らない番号には新しい番号を出す。試験用のサイトでは、そうなった。ただし、strict modeが拒むのは、サーバーが出していない番号だ。サーバーが出した本物の番号を、ほかの人が利用者に持たせる形の固定は、strict modeでは防げない。こちらは、ログインのときに番号を替えないと防げない。OWASPの手引きは、権限が変わった後(たとえばログインした後)に、番号を新しくするよう求めている。
"The session ID must be renewed or regenerated by the web application after any privilege level change within the associated user session."
(日本語訳: 利用者のセッションの中で、権限の水準が変わるたびに、Webアプリはセッションの番号を新しくしなければならない。)
点検には、ログインした状態の流れが要る
点検の条件として、ログインした状態の流れを確かめることが挙がった。Cookieの属性は、ログインページを開いただけでも見える。けれど、セッションの番号が、ログインの前と後でどう変わるかは、実際にログインしてみないと分からない。管理画面や会員のログインのように、ログインが前提の画面を持つサイトでは、「ログイン前のページが200で返った」だけでは、確かめたことにならない。
そこで、ナミオさんが試験用のサイトで、実際にログインを試した。会員のログインが通らなかった。直したせいかもしれないので、筆者が、試験用のサイトを直しの前の設定に戻し、ナミオさんにもう一度試してもらった。それでも通らなかった。だから、会員のログインが通らないのは、直しとは無関係と分かった。管理画面には、直しの前の状態でも入れた。
会員のログインが通らなかった理由は、別のところにあった
調べると、試験用のサイトの会員のデータが古く、本番の会員の一部が居なかった。これは、今回の直しとは別の話だ。
その後、直しを入れ直した。ナミオさんがパスワードを再設定して、直しの入った状態で、会員のログインが通った。管理画面にも、入れ直した後に入れた。つまり、管理画面には直しの前も後も入れて、会員のログインは、直しの入った状態で通った。ここまでで確かめたのは、「ログインが通ること」だ。ログインの前と後で、セッションの番号が替わるかどうかは、確かめていない。
ここで学んだのは、確かめるための道具が壊れていることもある、ということだ。「会員のログインが通らない」は、直しのせいにも見える。直しとは無関係と分かったのは、直しの前の設定に戻して、同じ確かめをもう一度したからだ。直す前の状態でも試すと、「直したから壊れた」と「元から壊れていた」を切り分けられる。
本番に出した ── 9ページで前と後を比べた
11月7日 11時23分50秒に、上書き用の設定ファイルへ足した
11時23分50秒に、試験用のサイトで通した2回目と同じ形で、本番の上書き用の設定ファイルに2つを足した。先に控えを取り、足す前の設定ファイルが想定どおりの状態であることを確かめてから、足した。ほかの行には、触っていない。
比べたもの
本番では、9つのページの前と後を比べた。比べた項目は、次のとおりだ。
| 項目 | 前と後の結果 |
|---|---|
| 応答の状態 | 9ページとも同じ |
| ページの大きさ | 同じ(トップだけ1バイトの差。ページに出る時計の表示の差) |
| 見出し・リンク・画像 | 同じ |
| 構造化データ | 同じ |
| PHPのエラー表示 | どちらも無し |
| Set-Cookie | 後はSameSite=Laxが付く(前は無し) |
| 偽のセッションの番号を付けた要求 | 新しい番号が返る(前はそのまま受け入れた) |
| エラーの記録 | 直した後の分は0件 |
見た目の同じさは、HTMLを取って、中身の数(見出し・リンク・画像・構造化データの数)で比べた。変わってほしいのはSet-Cookieと偽の番号への応答の2つで、それ以外は何も変わってほしくない。何も変わっていない、ということが、直した範囲が小さいことの確認になる。
測り方で1つ外した ── 確認用のスクリプトの結果と、curlの結果が食い違った
偽の番号への応答を確かめる確認用のスクリプトを最初に書いたとき、前も後も「新しい番号が返らない」と出た。直したのに変わっていない、とも読めた。ところが、curlという道具で同じ要求を送り直すと、試験用のサイトも本番も、新しい番号を返していた。
食い違いの原因は、確認用のスクリプトの側にあった。確かめ方が、新しい番号を見つけられていなかった。そこで、curlの結果を正とし、スクリプトは直す対象にした。確かめの結果が2つに割れたら、どちらかの道具を疑う。2つの道具で同じ要求を送り、答えが違うときは、より単純な道具の結果を先に信じて、複雑な方を調べ直す。
ブラウザでは見ていない
正直に書いておく。本番の確かめは、HTMLを取って、中身の数で比べた。ブラウザで画面を開き、表示された後の状態(DOM)を前と後で比べる道具が、この日は使えなかった。だから、ブラウザでは見ていない。HTMLの中身が同じで、応答も同じなので、画面は変わっていない見込みだが、画面を目で見て確かめたものではない。
Chromeの利用者には、どのくらい変わるか ── 見込み
Chromeは、指定が無いCookieをLaxとして扱う
ここは、見込みとして書く。Chromeは、SameSiteの指定が無いCookieを、Laxとほぼ同じ扱いにする。ただし、Cookieが作られてから2分間は、サイトをまたぐPOSTにも送られる例外(Lax+POST)があった、とChromiumの更新の記録にある。この例外は、一時的な措置で、いつか外す予定と原文は書いている。外れたかどうかは、確かめていない。この記録は、同じ動きを「SameSite=Lax by default」と呼んでいる。
"The target rollout population has been increased to 100% of users on Chrome Stable versions 80 and above, and the actual proportion of users with the new behavior enabled is now ramping up to 100% gradually."
(日本語訳: 対象の展開は、Chrome 80以上の安定版の利用者の100%に引き上げられた。新しい動きが有効になっている利用者の実際の割合は、100%へ向けて、少しずつ上がっている。)(2020年8月11日の行)
MDNも、同じことを一般的な言い方で書いている。
"If no SameSite attribute is set, the cookie is treated as Lax by default."
(日本語訳: SameSite属性が付いていないCookieは、既定でLaxとして扱われる。)
だから、Chromeを使う利用者にとって、当サイトのログインのCookieは、今回の変更の前から、Laxとほぼ同じ扱いだったと読める。SameSite=Laxを明示しても、Chromeの利用者の体感の変化は小さい、という見込みだ。これは見込みのままで、実際に測ってはいない。
大きいのはstrict modeと、ほかのブラウザ
ただし、ブラウザごとの既定は、同じとは限らない。OWASPの手引きは、既定値に頼らないよう書いている。
"Session cookies must explicitly set SameSite=Strict (preferred) or SameSite=Lax. Never use SameSite=None without Secure, and do not rely on the browser-default value, which varies across browsers and versions."
(日本語訳: セッションのCookieには、SameSite=Strict(望ましい)かSameSite=Laxを、明示して付けなければならない。Secureなしで、SameSite=Noneを使ってはならない。ブラウザの既定値に頼ってはならない。既定値は、ブラウザや版によって異なる。)
つまり、今回の変更で大きく変わるのは、2つの面だ。1つ目は、Chrome以外のブラウザや、版の古いブラウザで、SameSiteの扱いが明示的に揃うこと。2つ目は、strict modeにより、外から持ち込まれた偽の番号では、セッションが始まらなくなったことだ。後者は、どのブラウザでも同じように効く。これも、見込みで、利用者の体感の変化は、今回は測っていない。
担当サイトで確かめること ── 10項目のチェックリスト
自分で確かめる10項目
担当サイトで、明日から確かめられる10項目を挙げる。設定を読むのが難しければ、制作会社やサーバーの担当に頼んでよい。
- ログインページを開いて、応答のヘッダーのSet-Cookieを取る。ブラウザの開発者ツールのネットワークの画面で見られる。
- Set-Cookieに、Secure・HttpOnly・SameSiteの3つがあるかを、1つずつ見る。付いている属性が2つあっても、残りの1つが無いことがある。
- 設定ファイルに書いた指定の数と、応答に出た属性の数を、並べて比べる。合わなければ、書き漏らしではなく、上書きを疑う。
- セッションの設定を決める場所が、いくつあるかを数える。設定ファイル、CMSの部品、サーバーの設定の3つは、別々に持っていることがある。
- 読まれる順番を調べる。最後に読まれる場所が、最後に残る。直すときは、そこに書く。
- 偽の(サーバーが発行していない)セッションの番号を付けた要求を、試験用の環境から送り、新しい番号が返るかを見る。そのまま受け入れていたら、strict modeが効いていない。
- 設定の名前に「.」を含む設定は、書き方に注意する。設定を書く仕組みが「.」を区切りと読む場合は、配列のまま書き足す。
- 書き換えるときは、先に控えを取り、戻し方を決める。本番の前に、試験用の環境で一度試す。
- ログインした状態の流れ(ログイン前、ログイン後、ログアウト後)を、直した状態で一度通す。ログインの前と後で、セッションの番号が替わるかも見る。ログインできない原因が別にあれば、直す前の状態に戻して試して、切り分ける。
- 直した後、前と後で、応答の状態・大きさ・見出し・リンク・画像・構造化データを比べる。変わってほしい2つ以外が変わっていないことを見る。
制作会社・サーバーの担当への聞き方と、使える無料ツール
担当サイトを制作会社や運用会社に任せている場合は、次のように聞くと、状況が分かる。
- 「ログインのCookieに、SameSiteは付いていますか。応答のヘッダーで見せてもらえますか」
- 「セッションの設定を決める場所は、いくつありますか。最後に読まれるのは、どこですか」
- 「知らないセッションの番号を付けて要求すると、新しい番号が返りますか」
答えが「確かめたことはない」でも、責める話ではない。設定は、書いてあれば効いている、と思い込みやすい。確かめる仕組みが無かっただけのことが多い。
外から見える範囲を点検したいときは、🔧 【セキュリティ】WEBサイトの 外からできるセキュリティ対策監査ツール★ミエルン(会員登録が必要)が入口になる。ただし、これは外から見えるものしか確かめられない。セッションの番号の挙動は、別の確かめが要る。直す前と後で、ページの中身を並べて比べるなら、🔧 【メンテナンス】WEBサイトの状況チェック・比較ツール ★チガウン(会員登録が必要)が使える。画面を日付つきで残すなら、🔧 【運営】WEBサイトのスクリーンショット、まとめて撮っちゃおツール ★トレルンがある。
PHPのセッションの設定を見直すときは、PHP公式は、次の通常のリリースまで、セッションのアップロード進捗を0にするよう勧めた ── 設定の値・切り替えるコード・修正版に上げたあとの戻りを確かめる13項目(2026年10月時点)が、設定の値を確かめる順番の参考になる。担当サイトのPHPの版や設定を一覧に書き出す方法は、PHPの修正版が出た日に「どのサイトが当たるか」を数分で答えるには、担当サイトの一覧が要る ── 台帳の8列を埋めて確かめる13項目(2026年10月時点)にまとめてある。
この記事と同じ日に、解説記事も公開した。発端になったPHPのセッションの既定値の話はPHP 8.6.0のRC5は11月5日に出た試験版で、正式版は11月19日の予定。セッションの既定値3つが安全側に変わる ── ログイン・フォーム・外部との連携が壊れないかを試験環境で確かめる13項目(2026年11月時点)、Cookieの属性を応答で確かめる手順はCookieの設定にSameSite=Laxを書いても、後から読まれる設定に置き換えられて応答に付かないことがある ── ログインのCookieを応答のヘッダーで確かめる13項目(2026年11月時点)、HSTSの期間の確かめ方はHSTSのmax-ageは、ブラウザがHTTPSだけで開くと覚えておく秒数で、出典ごとに勧める長さが違う ── 担当サイトの値を秒から日に直して、延ばす前に戻せるかを確かめる13項目(2026年11月時点)にまとめてある。
当サイトの現在地 ── 実施したことと、これから
この記事で書いたことについて、当サイトの現在地を、正直に書く。
✅ 当サイト実施済 ログインのCookieにSameSiteが付いていないことを、応答のヘッダーで見つけた。設定が2か所にあり、後から読まれるCMSの部品がセッションの設定をまとめて置き換えていたことが理由だと、特定した。
✅ 当サイト実施済 置き換えの後に読まれる上書き用の設定ファイルに、SameSite=Laxとstrict modeを足し直した。試験用のサイトで1回目に書き方を誤って全ページをエラーにし、約1分で控えから戻した。2回目に配列のまま書き足して通した。
✅ 当サイト実施済 11月7日11時23分50秒に本番へ出した。9ページで前と後を比べ、応答・大きさ・見出し・リンク・画像・構造化データ・PHPのエラー表示が同じなことと、Set-CookieにSameSite=Laxが付くこと、偽のセッションの番号には新しい番号を返すこと、エラーの記録が0件なことを確かめた。
🔧 当サイトこれから 試験用のサイトの会員のデータを、本番に揃えるかどうかを決める。今は古く、本番の会員の一部が居ない。ログインを試験用で確かめるたびに、パスワードの再設定が要る状態は、続けにくい。揃えるなら、会員の個人情報を試験用に持ち込むことになるので、持ち込まずに済む方法も合わせて考える。
🔧 当サイトこれから 属性の確かめを、ログインのCookieだけでなく、ほかのセッションの属性にも広げ、手順に入れる。書いた設定と応答の属性を並べる確かめを、設定を変えるたびに行う形にする。
🔧 当サイトこれから 解説記事を書いた担当が、httpのままの要求を転送する応答にも、HTTPSを強制する印(HSTS)が付いている件を見つけた。直すかどうか、直すならいつ、どこに書くかを決める。
🔧 当サイトこれから ログインの後に、セッションの番号を替えているかを確かめる。strict modeは、サーバーが出していない番号を拒む設定で、サーバーが出した番号を持たせる形の固定は、ログインのときに番号を替えないと防げない。今は、替えているかを確かめていない。
🔧 当サイトこれから 本番で、すでにログイン中の人が、今回の直しで切れないかを確かめる。2026年11月7日の時点では、まだ確かめていない。
2026年11月7日 追記 ── 公開の後に、同じ日に確かめて直したこと
✅ 当サイト実施済 本番で、すでにログイン中の人が切れないか。ナミオさんが、本番の管理画面にログインしたまま開き直し、切れていないことを確かめた。
✅ 当サイト実施済 ログインの後に、セッションの番号を替えているか。当サイトのログインの処理を読むと、ログインに成功したときにセッションの番号を新しくし、古い番号を捨てる作りだった。管理画面のログインも、会員のログインも、同じ処理を通る。確かめたのはコードで、実際にログインして番号が替わるところは、まだ見ていない。
✅ 当サイト実施済 httpのままの要求を転送する応答のHSTS。転送の応答には付けず、HTTPSの応答にだけ付ける形に直した。試験用のサイトで確かめてから本番に出し、本番でも、転送の応答に付かなくなり、HTTPSの応答には今までどおり付いていることを確かめた。期間(30日)を延ばすかどうかは、まだ決めていない。
✅ 当サイト決定 試験用のサイトの会員のデータは、本番に揃えないことにした。本番の会員の個人情報を、試験用のサイトに持ち込まないためだ。ログインを試験用のサイトで確かめるときは、パスワードを再設定した試験用のサイトの会員で確かめる。
まとめ
持ち帰ってほしいことは、5つだ。
- 設定ファイルに書いてあることと、応答に出ていることは、別だ。書いた行の数と、応答の属性の数を並べて比べる。
- セッションの設定が2か所にあると、後から読まれる側が、先に書いた指定をまとめて置き換えることがある。直すときは、最後に読まれる側に書く。
- SameSiteは、応答のSet-Cookieで確かめられる。strict modeは、応答には現れない。偽の番号を付けた要求を送って、新しい番号が返るかで確かめる。
- 設定の名前に「.」を含むときは、設定を書く仕組みの読み方に注意する。試験用の環境で一度試し、控えと戻し方を先に決める。
- 確かめの結果が道具によって食い違ったら、どちらかの道具を疑う。ログインを伴う確かめでは、直す前の設定に戻して試して、元からの不具合と切り分ける。
確かめていないことも書いておく。1つ目は、ブラウザでの表示の確認だ。この日は、ブラウザで画面を開いて比べる道具が使えず、HTMLの中身で比べた。2つ目は、利用者の体感の変化だ。Chromeでは小さい見込みだが、実際に測ってはいない。3つ目は、ログインの前と後で、セッションの番号が替わるかだ。ログインが通ることは確かめたが、番号が替わるかは確かめていない。4つ目は、本番ですでにログイン中の人が、今回の直しで切れないかだ。2026年11月7日の時点では確かめていない。5つ目は、ログインのCookie以外のセッションの属性だ。広げて確かめるのは、これからだ。6つ目は、試験用のサイトの会員のデータのずれが、ログイン以外の場面にも影響していないかだ。
関連 archives(連載軸として読む)
- Basic認証のパスワードのファイルが、公開の場所の中に9本あった ── 外からは全部403だったが、読めなかったのは1つの決まりのおかげだった。確かめ方と、公開の外へ移した記録 ── 自分のサーバーの中を数えて、その日のうちに直した記録(10月30日)
- PHPの2件の脆弱性が悪用リストに載り、期限は10月29日だった ── 期限の日に当サイトで確かめた4つと、自分の記事の言い過ぎ、期限を自分のサイトの期限に読み替える方法 ── 期限の日に、当サイトの設定を確かめた記録(10月29日)
- 圧縮の部品(Brotli)の脆弱性は、縮めて送る側ではなく「元に戻す側」の話だった ── 当サイトが外から圧縮を受け取る場所を数え、その日のうちに塞いだ記録と、同じ日にサーバーが止まったあとの確かめ方 ── 見つけた日のうちに塞いだ記録(10月28日)
- PHPの修正を入れても、版の番号も「作った日」も入れ替える前と同じ文字だった ── 修正が入ったかを値で確かめる4つの方法と、3本目の知らせ(CVE-2026-115560)を当サイトで確かめた記録 ── 表示ではなく値で確かめるという考え方の元になった記事(10月26日)
- 控えファイルを外から確かめた日 ── 当サイトで読めたのは25本。「403でも置かない」理由と、次から積もらない手順 ── 設定の控えを、公開の外に置く理由の記事(10月23日)
- PHPの重大な脆弱性「php2shell」を、初心者から上級者まで1本で ── 自分のサイトは関係あるか、更新の順番、更新の後に確かめること、攻撃を受けたかの調べ方、当サイトとチームの記録 ── PHPの更新の後に確かめる項目をまとめた記事
解説記事では、PHP公式は、次の通常のリリースまで、セッションのアップロード進捗を0にするよう勧めた ── 設定の値・切り替えるコード・修正版に上げたあとの戻りを確かめる13項目(2026年10月時点)のほか、PHPの修正版が出た日に「どのサイトが当たるか」を数分で答えるには、担当サイトの一覧が要る ── 台帳の8列を埋めて確かめる13項目(2026年10月時点)、公開の場所に残った控えファイルは、名前で探して状態コードで確かめ、外へ移す ── 自社と担当サイトの.bak・.old・日付付きの写しを棚卸しする13項目(2026年10月時点)もあわせて読める。ツールでは、外から見える範囲の点検を、🔧 【セキュリティ】WEBサイトの 外からできるセキュリティ対策監査ツール★ミエルンで始められる(会員登録が必要)。
出典
すべて2026年11月7日に開いた。
- MDN: Using HTTP cookies(SameSite属性と、指定が無いときの扱い)
- PHP Manual: Session Runtime Configuration(session.cookie_samesiteとsession.use_strict_mode)
- PHP Manual: session_regenerate_id(セッションの番号を新しい番号に替える関数)
- OWASP: Session fixation(セッション固定の説明)
- OWASP: Session Management Cheat Sheet(SameSiteの扱いと、権限が変わったときの番号の更新)
- Chromium: SameSite Updates(Chromeでの展開の経緯)
WEBサイト