サブドメインでCookieを共有するのにハマった
LaravelではデフォルトでCookieは暗号化される仕様になっているようで、この挙動によって多分普通に使ってるとサブドメイン間でCookieが共有されないと思います。Cookieに関するドキュメントはこちら:
HTTP Requests - Laravel - The PHP Framework For Web Artisans
All cookies created by the Laravel framework are encrypted and signed with an authentication code, とあるんですが、authentication codeってなんなのさ状態。で、さらに厳密に言うと、共有はされているのにLaravelのCookie Facadeから取得できない状態。余計に分かりづらい。
例
メインサイトAが a.example.com で稼働していて、それとは別の用途で サイトBb.example.com が稼働しているとします。サイトBは画像アップロードとかそういう用途で。
この場合に両サイトでCookieを共有するには、domainに .example.comと書きますよね。Laravelなら config/session.php の domain のキー項目に設定します:
// config/session.php line:138行目付近
- 'domain' => nullundefined
+ 'domain' => '.example.com'undefined
または生成時にCookie::make()の第五引数に指定することができます:
@sugimoto1981 試してないですが$response->withCookie(cookie('name', 'value', $minutes, $path, $domain));となっているので第5引数を'.example.com'とかすれば行けそうな気がします。
— MATSUO Masaru (@localdisk) 2015, 5月 27
ありがとうございます!
で、サイトAでログインした後に、なんらかの記憶トークンをCookieにセットし、この状態でサイトBに移動すると…Cookieが読み取れない。ここで問題なのは、ChromeのDevtoolやCOOKIEをdumpすると値があるにも関わらず、Cookie Facade経由のCookie::getがnullになることです。COOKIEの値はそもそも暗号化されてて使えない。おそらく、というかきっと復号に失敗している。authentication code によって。
対策と解決
中のコード読んだりしてて気づいたけど、LaravelはCookieのencryptにconfigの key の値を使うみたい(.envのAPP_KEYの項目でセットされますね) なので、これをサイトAとサイトBで同じものにセットする事で、サブドメイン間でCookie Facadeがちゃんと動作するようになりました。
このkeyを同一にすることによるセキュリティへの影響は未検証ですが、まぁ同一のアプリケーションだから漏洩しなければ大丈夫でしょう。
まとめ
片方だけステージングにしてて、keyの相違が発生してCookieが取れない、とかなりそうなので注意が必要ですね。 機能ごとに分散して稼働させるケースには注意が必要。自分はSSOの認証サーバ周りの実装をしてる時にハマりました。
ちょっとしたことだけど、解決策はググっても見つけられなかったし、そもそも公式ドキュメントがわりとあっさりしててかなりトライアンドエラーを強いられている。設定項目とかコード断片とかは、せめてどのファイルに書くのかくらいは明示して欲しい(どこに書いても動作したりするから余計に)。拡張する時にとても困る。それ以外はとても便利なFWだとは思います、はい。
現場からは以上です。