Cookieのセキュリティ周りでいちばんややこしいDomain属性をしっかり理解する

先日[某所](https://commew.net/)の勉強会でCookieのセキュリティ周りの話をしていたのですが、その中で自分のDomain属性の理解が不十分だということに気付きました。

Cookieのセキュリティ関係の属性としては、`Domain`, `Secure`, `HttpOnly`などがあります。`Secure`は設定されていればHTTPSで通信していなければCookieを送信しない。`HttpOnly`はJavaScriptからCookieにアクセスさせない、とどちらもわかりやすい機能ですが、`Domain`については割と複雑です。

複雑だからといって理解が不十分なままにしてはおけない、ということで調べてまとめてみました。

この記事ではサーバからクライアントへの`Set-Cookie`ヘッダによるCookieの送信を「(Cookieの)設定」と、クライアントからサーバへの`Cookie`ヘッダによるCookieの送信を「(Cookieの)送信」と呼びます。


# Domain属性は、Cookie送信時にどう働くか

順番としてはサーバからクライアントにCookieを設定した上で、クライアントからサーバに設定されたCookieを送信、という流れですが、Cookie送信時の挙動の方がわかりやすいため、まずこちらから説明します。

これは簡単で、送信時のDomain属性の働きは「設定された値と送信先のサーバのドメインがマッチするときにだけCookieを送信する」となります。

ただしマッチする方法には完全一致と後方一致の2パターンあります。完全一致は設定時にDomain属性を指定しなかった場合に、設定したサーバのドメインで完全一致になり、指定した場合は常に後方一致になります。

Domain属性の値          | 送信先ドメイン  | 送信     |
----------------------- | --------------- | -------- |
未指定(example.com)     | example.com     | される   |
未指定(example.com)     | foo.example.com | されない |
未指定(foo.example.com) | example.com     | されない |
未指定(foo.example.com) | foo.example.com | される   |
example.com             | example.com     | される   |
example.com             | foo.example.com | される   |
foo.example.com         | example.com     | されない |
foo.example.com         | foo.example.com | される   |

なお後方一致は階層的なものなので、`example.com`を指定した場合に、`abcdexample.com`に送信されることはありません。


# Domain属性の設定に制限はあるのか

ご存知の通り、悪意のあるサーバから攻撃対象のサーバに送信されるCookieを自由に設定できてしまうと、セッション固定攻撃の要因になってしまい危険です。それを防ぐためのメカニズムはどうなっているのでしょうか。

設定できるDomain属性には制限があります。制限に反するDomain属性を設定しようとしても、ブラウザに拒否されて設定できません。ブラウザによってはコンソールログなどにCookieを拒否した旨のメッセージが出たりします。

では具体的にどういう制限があるのか。**Cookieを設定するサーバ自身のドメインか、そのドメインより上位の階層のドメイン**のみ設定できます。

Cookieを設定するサーバのドメイン | Domain属性に設定するドメイン | 設定の可否 |
-------------------------------- | ---------------------------- | ---------- |
example.com                      | example.com                  | 可         |
example.com                      | foo.example.com              | 否         |
foo.example.com                  | example.com                  | 可         |
foo.example.com                  | foo.example.com              | 可         |
bar.example.com                  | foo.example.com              | 否         |
abc.example                      | example.com                  | 否         |

直感的でないのは、自身より下位の階層(`example.com`の場合の`foo.example.com`)のドメインを設定できないことです。また、兄弟関係にある階層のドメインも設定できません。ただしこれらのパターンに関しては、どちらも`example.com`を設定すれば送信される対象にはなります。


## ということで、CookieのDomain属性は安全です……あれ？

おそらく気付かれたと思うのですが、`example.com`から見て`com`は上位の階層のドメインです。では`example.com`から`com`をDomain属性に設定して、`.com`のすべてのドメインに向けたCookieを設定できてしまうのでしょうか。

現在の仕様(RFC 6265)では、これは制限されています。ブラウザは、`com`のような公共のドメイン接尾辞(public suffix)[^1]を受け付けないように決められています。[^2]

公共のドメイン接尾辞のリストは、[Public Suffix List](https://publicsuffix.org/)で公開されています。

このようにリストの形になっているのは、どのレベルのドメインの所有者を同一と見做すかのルールが存在しないからでしょう。`com`のようなトップレベルドメインのサブドメインはおそらくそれぞれ別の所有者のものと考えられそうですが、`co.jp`や`ne.jp`のようなセカンドレベルドメインの場合は判断できません。`co.jp`や`ne.jp`はサブドメインに別々の所有者がいる公共のドメインですが、`jprs.jp`は株式会社日本レジストリサービスの所有するドメインで、おそらくそのサブドメインのすべても同社が所有しています。


## 公共のドメイン接尾辞のリストがあるから安心、かというと……

じつは安全でない場合がいくつかあるようです。


### Cookie Monster問題

公共のドメイン接尾辞のリストは、割と最近(2008年)に作成されたもので、また現在ある程度有効なCookie仕様であるRFC 6265もさらに後の2011年に初めて公開されたものです。

それ以前はおそらくブラウザごとに独自の対応をしていた面が強いと思われ、実際`co.jp`のようなドメインをDomain属性に設定できるという話さえありました。

このような、公共のドメインをDomain属性に設定できてしまう脆弱性をCookie Monsterと言うようです。この脆弱性は2021年現在も部分的に残っているようです。


参考:
公共のドメイン接尾辞のリストの開始時期は以下のPDFから。
[Public Suffix Listとその問題点(PDF)](https://dnsops.jp/bof/20080709/dnsops-jp-20080709.pdf)

Cookie Monster脆弱性については[体系的に学ぶ 安全なWebアプリケーションの作り方](https://www.sbcr.jp/product/4797393163/)の初版・第2版等から。


### 実質的に公共のドメインになっている、レンタルサーバ等のドメイン

私の愛用している[さくらのレンタルサーバ](https://www.sakura.ne.jp/)では、利用者に`好きな文字列.sakura.ne.jp`というサブドメインを用意してくれます。

この場合の`sakura.ne.jp`は公共のドメインではなく、そのためサブドメインから`sakura.ne.jp`のCookieが設定できるようです。


参考:
利用者にサブドメインを提供するレンタルサーバでのセッション固定攻撃の可能性について。
[セッションフィクセイション脆弱性の影響を受けやすいサイトとは | 徳丸浩の日記](https://blog.tokumaru.org/2012/12/what-kind-of-sites-are-vulnerable-to-session-fixation.html)


### ではどうするか

昔と比べれば外部からのCookieの設定は難しくなってはいるようですが、それでもまだしばらくはCookieは外部から設定される前提でいた方がよさそうです。

また外部からのCookieの設定によるセッション固定攻撃に対しては、「体系的に学ぶ 安全なWebアプリケーションの作り方」やIPAの[安全なウェブサイトの作り方](https://www.ipa.go.jp/security/vuln/websecurity.html)にあるように、ログイン時に常にセッションIDを再生成しましょう。


# おまけ: 3rd party cookieとはなんなのか

Cookieの制限について考えていると、プライバシー方面でよく耳にする3rd party cookieとはなんなのか、という疑問が湧いてきました。

ここまで書いてきたように、Cookieは細かい問題はあるものの、概ね設定できる送信先ドメインは制限されています。

今回の記事の主題ではないため簡単に説明すると、3rd party cookieとは、訪問したサイトから読み込まれた外部の画像やJavaScript経由で設定される、外部のドメインに送信されるCookie, ということのようです。

`example.com`内のページに`https://adserver.example/ad.jpg`のような画像への参照がある場合、意図せず`adserver.example`からCookieを設定されてしまいます。これを3rd party cookieと呼ぶようです。

セキュリティ的に問題になることはないですが、この手法によるユーザの追跡がプライバシー方面ではよく問題になっています。


参考:
3rd party cookieとはなにかについて。
[7.1. 第三者主体によるクッキー / Cookies: HTTP State Management Mechanism （日本語訳）](https://triple-underscore.github.io/http-cookie-ja.html#third-party-cookies)


# 参考

Cookieの仕様(RFC)の日本語訳。Cookieは長らく仕様ベースで実装されていなかったようですが、このRFC以後はある程度仕様ベースで実装されていきそうです。
[Cookies: HTTP State Management Mechanism （日本語訳）](https://triple-underscore.github.io/http-cookie-ja.html)


# この記事のライセンス

![クリエイティブ・コモンズ・ライセンス](https://i.creativecommons.org/l/by/4.0/88x31.png)
この文書は[CC BY(クリエイティブ・コモンズ表示4.0国際ライセンス)](http://creativecommons.org/licenses/by/4.0/)で公開します。


[^1]: この場合の公共(public)のドメインとは、サブドメインを(お金を払って、またすでに使われていなければという制限はあるものの)自由に登録できるドメイン、ということです。逆にそのように公共なドメイン上に登録されたドメインは基本的には私的なドメインとなり、所有者以外がサブドメインを登録することはなくなります。

[^2]: 正確には、ブラウザの設定上で公共のドメイン接尾辞を却下するよう設定されている場合は受け付けない、となっています。私はそのような設定が可能なブラウザを見たことがありませんが。