同一オリジンとかSameSiteとかを完全に理解した
Webの世界は『同じサイトに対して〜』的な話が色々あって難しいので、ちょっとばかり完全に理解することにした。
同一オリジンとは
ブラウザから見た時のコンテンツの生成元をオリジンという。RFC 6454で定義されているらしい。
オリジンはスキーム(プロトコル)、ホスト(ドメイン)、ポートで定義される。
例えばhttp://gengogo5.com:8080
なら、スキームは http
でホストは gengogo5.com
ポート番号は8080
。
この3つのどれかが異なるもの同士は同一オリジンとはみなされない。
なので次の4つは全部別のオリジンということになる。
http://gengogo5.com/
https://gengogo5.com/
https://sub.gengogo5.com/
https://gengogo5.com:8080/
サブドメインもホストが違うのでNG。紛らわしいけどサブディレクトリは同一オリジン。
オリジンが異なる場合にはCORSで制約を受けることがある。CORSに踏み込むと主題と逸れるので別の機会に復習することにする。
localhostと127.0.0.1は同一オリジンなのか
個人的に理解が怪しいと思っていた点がホスト。
http://localhost:80
とhttp://127.0.0.1:80
は同一オリジンか?という話。
なんとなく直感的には同じようなイメージを持ちそうだけど、ホストが違うので同一オリジンではない。IPアドレスではなくてホストで区別している。
確かにlocalhost
と127.0.0.1
にそれぞれリクエストしてみると、リクエストヘッダのHost
の内容は異なっている。
❯ curl -v http://localhost/
* Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.77.0
> Accept: */*
❯ curl -v http://127.0.0.1/
* Trying 127.0.0.1:80...
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.77.0
> Accept: */*
teratailで同じ質問をされている方がいた。
よくよく考えれば、同一IPアドレスを同一オリジンとみなしてしまうと、DNSラウンドロビンだったりAレコードが変わった際に別オリジン扱いになるのでそれはそう、という気がする。
Cookieの送信先は同一オリジンなのか
Cookie の送信先についても、CORS と似てなんとなく『同じサイトは許す』的なイメージがあるが、CORSより厄介。
Cookieは後述する属性を考えない場合、発行元と同じドメインに対してのリクエストで送信される。サブドメインが異なる場合は送信されない。
ドメインが一致していれば送信されるということは、http
とhttps
では混同されるし、ポート番号が違っても送信されることになる。従って『Cookieの送信先は同一オリジンではない』と考えるのが妥当そう。
また、ドメインの一致を見ているということは、IPアドレスを直指定してアクセスした場合はドメインが異なるため、Cookieが送信されないことになる。
Cookie送信先をゆるくしたり厳しくしたりする
『サブドメインとCookieを共有したい』とか、『特定のパスに対してのリクエストでだけCookie送信させたい』といったニーズに応えるために Domain 属性と Path 属性がある。
Domain 属性は Cookie の送信先の制限を緩和するもので、Set-Cookie時にDomain 属性でgengogo5.com
が指定されたら、そのCookieはgengogo5.com
だけでなくsub.gengogo5.com
へのリクエストの時にも送信される。
Path 属性は Cookie の送信先をより制限するためのもので、Path属性に指定されたパス配下に対してのリクエストでのみ Cookie が送信される。サブディレクトリ配下も送信対象になるので、/
が指定されていれば制限なしになる。
http 通信では送ってほしくない、というときには Secure 属性というのがある。
SameSite属性というもの
Cookie には SameSite 属性というやつもいる。
Lax
かStrict
かNone
の3択で、モダンブラウザと言われるブラウザたちの最新バージョンではLax
がデフォルト。
Strict
はクロスサイトリクエストでのCookie送信を許さない。
None
はクロスサイトリクエストをなんでも許す。
Lax
はクロスサイトリクエストの一部でCookie送信を許さない。
Lax
については CSRF からの保護が主な目的なので、 POST メソッドでのクロスサイトリクエストでは Cookie が送信されない。じゃあ GET なら全部いいのかというと、top-level navigation
という考え方があって、これに該当する GET なら良いらしい。top-level navigation
はアドレスバーに表示されているURLが変わる画面遷移。逆にこれに該当しない GET とは?というと、インターネット広告表示がまさにこれ。うーん、難しい。
参考文献
このあたりの話で混乱しないためには、『同じサイト』とか『同じサーバ』といったふんわり理解ではなく、ドメインやオリジンなどそれぞれの用語の定義や、何をもって同一と判断するのかをおさえておくのが重要そう。