絵文字アイコン

クロスサイトでCookieを扱う

クロスサイトでCookieを保持して使えるようにしたいという時に最終的にしたことのメモ

結論

localhostをSSL化&Set-CookieのSecure,SameSite,Domain属性を指定してやり取りするサイトがそのサブドメインになるようにしたら解決できた

やりたかったとこ

まずこれは業務内での話で、ローカルで開発を行う際にはバックエンドのAPIをdev環境のものを使うようにしている。
その際にバックエンドのエンドポイントはhttps://xxx.dev.yyy.devのようになっており、ローカルのhttp://localhost:3000からアクセスするとクロスサイトになる。

開発しているアプリケーションでは、アクセストークンがないとAPIへのリクエストが失敗するようになっており、フロント側でもmiddlewareでアクセストークンの認証が切れていないかどうかの確認をし、もし切れている場合はログイン画面に飛ばすという処理を行いたかった。
しかし、localとdevはクロスサイトのため/loginのAPIを叩いてログインIDとパスワードを送信し、成功したとしてもSet-Cookieによるアクセストークンの保存ができない。

理由としては以下のようになっている(引用:MDN

  • SameSite に関する標準規格が最近変更されました
  • Cookie に SameSite=None が付いた場合は、 Secure 属性も指定することになりました(安全なコンテキストが必要になりました)。
  • 同じドメインの Cookie であっても、異なるスキーム (http: か https: か) を使用して送信された場合は同じサイトと見なされなくなりました。

Samesite属性は異なるサイト間でのCookieの送信を制限するためのもので、Noneを指定すると異なるサイト間でも送信できるようになるが、Secure属性も必要になる。
そのため、ローカルのhttp://localhost:3000からhttps://xxx.dev.yyy.devにアクセスする場合は、Secure属性がないためCookieを保存することができない。

Secure属性を付与すると「HTTPS プロトコル上の暗号化されたリクエストでのみサーバーに送信」するようになるため、両者のサイトはhttpsでないといけない。 なのでまずはローカルをSSL化する必要がある。

開発はNext.jsで行っており、13.5から開発サーバーをhttpsで簡単に立ち上げられるようになったため、それを利用することにした1
以下のように--experimental-httpsフラグを追加してnext devを実行すると、自動的にlocalhostがhttps化される。

next dev --experimental-https

ただ、SSL化しただけではダメだったので、他の要因を探したが、結局Domain属性を指定すれば同じルートドメインを持つサブドメイン間でCookieを共有することができるということを知り、それで解決できた。
つまり、Set-CookieDomain属性にdev.yyy.devを指定して、ローカルをhttps://localhost.dev.yyy.dev:3000にすることで解決できた。

Domain属性とは以下のようなものである(引用:MDN

  • Domain 属性は、Cookie を受信することができるホストを指定します。サーバーが Domain を指定しなかった場合、ブラウザーは既定でドメインを Cookie を設定したのと同じホストとし、サブドメインは除外します。
  • Domain が指定された場合、サブドメインは常に含まれます。したがって、 Domain を指定すると省略時よりも制限が緩和されます。ただし、サブドメイン間でユーザーに関する情報を共有する場合は有用になるでしょう。
  • 例えば、Domain=mozilla.org を設定すると、developer.mozilla.org のようなサブドメインも含まれます。

これでクロスサイト間でのCookieのやり取りができるようになった〜! (Cookieについての理解が浅く手探りで試しながらだったのでいかなり沼った😵‍💫)

Footnotes

  1. HTTPS for Local Development

GitHubで編集を提案