cookieのDomainとSameSite属性についてのまとめ

Cookieの`Domain`と`SameSite`について、毎回調べて思い出す必要があったので、自分用にまとめる。
以下、属性の並びは、[mdn web cocs (Set-Cookie)](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie) に従う。
上記のドキュメントを読めば簡単に理解出来るもの（`Domain`と`SameSite`以外）は、説明を割愛するが、一部記載がある場合もあり。

# `Expires=<date>` （省略可）

割愛

- 「セッションクッキー」と「永続的クッキー」について
  - セッションクッキー（Session Cookie） 
    - Expires や Max-Age ディレクティブが指定されていないクッキー。クライアントが終了したときに削除される。 
  - 永続的クッキー（Permanent Cookie）
    - Expires や Max-Age ディレクティブが指定されたクッキー。クライアントが終了しても削除されない。 

# `Max-Age=<number>` （省略可）

割愛

# `Domain=<domain-value>` （省略可）

- クッキーを送信する先のホスト（つまり、クッキーの受け手）を定義する。
- 省略した場合は、クッキーを送信するサーバのホスト名になり、サブドメインは含まれない。
  - **つまり、何も指定しないのが、セキュリティ面で一番強固**。
- ドメインを指定した場合は、すべてのサブドメインが常に含まれる。
  - ドメイン名の前のドット (`.example.com`) は無視される。
    - 設定は可能だが、`.example.com`も`example.com`もクッキーを送るドメインの範囲は同じ。
- 複数の値を設定することは出来ない。
- 無効な（ユーザーエージェントに拒否される）設定の例
  - オリジンのサーバーを含まないドメインに所属するクッキーは、ユーザーエージェントが拒否する。
    - `Domain=somecompany.co.uk`を`originalcompany.com`でホスティングされたサーバーから設定しようとすると拒否される。以下原文の例では、オリジンが`foo.example.com`で、`example.com`や`foo.example.com`を設定した場合は問題ないが、`bar.example.com`や`baz.foo.example.com`を設定した場合はユーザーエージェントが拒否する。
    - [原文](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.2.3)（以下、抜粋）
      - The user agent will reject cookies unless the Domain attribute
   specifies a scope for the cookie that would include the origin
   server. For example, the user agent will accept a cookie with a
   Domain attribute of "example.com" or of "foo.example.com" from
   foo.example.com, but the user agent will not accept a cookie with a
   Domain attribute of "bar.example.com" or of "baz.foo.example.com".
  - 提供するドメインのサブドメインへのクッキーは拒否される（上記の説明に包含されるが、念の為記載）。
    - `Domain=foo.example.com`を `example.com` でホスティングされたサーバーから設定しようとすると拒否される。

# `Path=<path-value>` （省略可）

https://www.javadrive.jp/javascript/webpage/index18.html の「Cookieを送信するパス(Path属性)」を参照。

# `Secure` （省略可）

割愛

# `HttpOnly` （省略可）

割愛

# `SameSite=<samesite-value>` （省略可）

- `Domain属性`が、「サーバ → クライアント」のクッキーの送信条件を定義するのに対して、同属性は「クライアント → サーバ」のクッキーの送信条件を制御する。
- 具体的には、クロスサイトリクエストでクッキーを送信するかどうかを制御し、CSRFに対するある程度の防御を提供する。
- cross-site（クロスサイト）の定義について（[参考](https://security.stackexchange.com/questions/223473/for-samesite-cookie-with-subdomains-what-are-considered-the-same-site)）
  - same-site（同一サイト）の定義は、「スキーム（`http://`部分）」及び、セカンドレベルドメイン（*example.com* の *example*）とトップレベルドメイン（*example.com* の *com*）のコンビネーションで判断される。例えば、*https://foo.example.com* と *https://bar.example.com* や *https://one.two.example.com* は同一サイトとみなされる。
  - 上記以外が、クロスサイトとみなされる。
  - 但し、[ここ](https://security.stackexchange.com/questions/223473/for-samesite-cookie-with-subdomains-what-are-considered-the-same-site)に書かれている通り、[PUBLIC SUFFIX LIST](https://publicsuffix.org/learn/)というのがあり、ここに載っているサイトは、上記のルールで同一サイトであるとみなされても、クロスサイトとみなされる。
    - 例えば`my-site.azurewebsites.net`と`your-site.azurewebsites.net`は、クロスサイトとみなされる。

以下、設定可能な値。

## Strict
 
- ブラウザーが同一サイトのリクエストに対してのみクッキーを送信する。

## Lax

- クロスサイトリクエスト（画像やフレームを読み込むリクエスト）ではクッキーを送信しない。
- ユーザが外部サイトから元のサイトに戻る時（例えば、リンクをたどる時）にはクッキーを送信する。
- `SameSite`が設定されていない時のデフォルトの動作。
 
## None

- ブラウザーがクロスサイトと同一サイトの両方のリクエストでクッキーを送信する。
- 同時に、`Secure`属性も設定する必要がある（例:`SameSite=None; Secure`）。

# 参考文献

- https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie
- https://www.javadrive.jp/javascript/webpage/index18.html

# その他（SPA時の、クライアントとサーバのドメイン名についての考察）

- `Domain`の仕様（オリジンのサーバーを含まないドメインに所属するクッキーは、ユーザーエージェントが拒否する）を考えると、同じドメインである必要がある。
- （上記の条件で十分だが）、`SameSite`の仕様も考慮して、SPAの場合、サーバとクライアントのドメインを揃える（`api.example.com`, `www.example.com` 等）。そうすれば、`Strict`が設定できる。

# 開発環境についての補足

## 前提

- 本番環境はSSL通信前提だが、SPAの開発環境でSSL通信ができない場合がある。
- ドメイン名は以下の通り。
    - サーバ: api.example.com
    - フロントエンド: front.example.com

## 考察

「スキーム（`http://`部分）」が異なると、same-site（同一サイト）とみなされない。
つまり、フロントエンドとサーバが「両方非SSL」or「両方SSL」で揃っていれば、非SSL（secure属性なし）でも通信可。よって、サーバへのアクセスを非SSLで行えば解決（しそうだが、試したことはない）。