概要
-
Originはスキーム+ホスト(+ポート) -
Siteは登録可能なドメイン(registrable domain) - サブドメインが信頼できない場合、
SameSite cookiesはCSRF対策として不十分
ざっくりと
例えば、http://example.com/app/index.htmlというURLがあったとします。
乱暴に言ってしまうなら、この中でOriginとSiteは以下のようになります。

ここで大切なのはOriginはSiteを包含する概念であるということです。
Origin
OriginはURLのスキーム+ホストにより表される概念です。
つまり、URLの最初の/より左側と言って良いでしょう。
最近のブラウザだと下の画像のように、Origin部がハイライトされます。

厳密に言うとOriginの概念はポート番号を含みますが、通常はスキームによりポートも自動で決まるため無視されます。
理解のために、**同一オリジン(Same Origin)**であるようなURLの例を示します。
以下のURLはすべてhttp://example.comと同一オリジンです。
/* http://example.comと同一オリジン */
http://Example.com:80
http://example.com/app/
http://example.com/app/index.html
反対に、http://example.comと**クロスオリジン(Cross Origin)**の関係にあるようなURLの例を示します。
/* http://example.comとクロスオリジン */
http://example2nd.com // ホストが異なる
http://foo.example.com // ホストが異なる
http://example.com:8080 // ポートが異なる
https://example.com // スキームが異なる
Site
初めからテクニカルタームとして定義され利用されてきたOriginと異なり、"サイト(Site)"という言葉は一般に広く利用されていて、かなり曖昧な理解がされています。
MDNによると、Siteは**登録可能なドメイン(registrable domain)**により決定されるそうです。
...新たな概念が現れました。"登録可能なドメイン"とは何でしょうか?
登録可能なドメイン(registrable domain)
登録可能なドメインの最もシンプルな例は、トップレベルドメイン(Top Level Domain, TLD)にラベルを付けたものです。
例えば、mysite.comというドメインが取りたいという状況を考えてみます。
この時、お名前.comやGoogle Domainsといった適当なドメイン取得サービスでmysite.comが利用可能な状態かを調べ、使えるなら入金してドメインの利用権を得る、といった手続きをとるかと思います。
ドメイン取得サービスを利用しドメインの利用権を"登録"できる、すなわちmysite.comは登録可能なドメインといえます。
じゃあURLのうちA.comみたいな部分がSiteなのか、と言うとそうでもありません。
サブドメインが登録可能なドメインである場合が存在します。
このような例としてよくあるのが、Github Pagesです。
Github Pagesを公開すると、[アカウント名].github.ioというドメインが割り当てられます。この[アカウント名].github.io、実は
github.ioのサブドメインであるにもかかわらず、登録可能なドメインとして知られています。
このgithub.ioのように、トップレベルドメインではないものの同等な扱いをされるドメイン群を、実際のトップレベルドメインと合わせてPublic Suffixまたは**eTLD(effective Top Level Domain)**と呼びます1。
Public Suffixをいくつか例示します。
/* Public Suffix(eTLD)の例 */
com
org
co.jp
東京.jp
github.io
netlify.app
Public Suffixにラベルを付けたものをeTLD+1といいます。
例えばfoo.github.ioはeTLD+1です。
まとめるなら、Site=登録可能なドメイン=eTLD+1と言ってよいでしょう。
例
以下に挙げるのは、**同一サイト(Same Site)**であるようなURLの例です。
/* 同一サイトなURLの組 */
http://example.com/app1/ // eTLD(com)とラベル(example)が一致。
http://example.com/app2/ // 同一オリジンでもある。
http://foo.example.com // eTLD(com)とラベル(example)が一致。
http://bar.example.com // 同一オリジンではない。
http://example.com // eTLD(com)とラベル(example)が一致。
https://example.com // 同一オリジンではない。
反対に、**クロスサイト(Cross Site)**であるようなURLの例も示します。
/* クロスサイトなURLの組 */
http://foo.com
http://bar.org // 何も一致しない。
http://foo.com // eTLD(com)は一致。
http://bar.com // +1(foo, bar)が一致しない。
http://foo.github.io // eTLD(github.io)は一致。
http://bar.github.io // +1(foo, bar)が一致しない。
OriginとSiteの比較表
ここまでの内容を例でもってまとめます。
先に述べたようにOriginはSiteを包含する概念なので、**"クロスオリジンだが同一サイト"**という状況はありますが、その逆はありません。
| 同一オリジン 同一サイト |
クロスオリジン 同一サイト |
クロスオリジン クロスサイト |
|---|---|---|
http://example.com/app1/http://example.com/app2/
|
http://example.com/app1/https://example.com/app2/
|
http://foo.com/app/http://bar.com/app/
|
http://Example.com:80http://example.com
|
http://foo.example.comhttp://bar.example.com
|
http://foo.github.iohttp://bar.github.io
|
CSRF対策としてのSameSite cookies
CSRFに対するシンプルかつ効果的な防護策として知られているのが、SameSite属性をLaxに設定することです。
これにより、悪意あるサイトから自サイトのCookieを利用することを防げます。
実際、今日のブラウザではSameSite=Laxがデフォルト値となっており、ほとんどのCSRFを防ぐことが出来ているはずです。
しかし、ここで気を付けなければならないのはSameSite属性はクロスサイトな攻撃には有効だが、クロスオリジンな攻撃には対処できないということです。
例えば、mypaas.comというドメインでPaaSサービスを展開し、各ユーザーにmypaas.comのサブドメインを配布することになったとします。
あるユーザー"Alice"がこのサービスを利用し、alice.mypaas.comというドメイン上でセッション情報を利用するアプリケーションを展開しました。
一方で、悪意あるユーザー"Eve"がeve.comでサイトを公開し、このドメイン経由でalice.mypaas.comに対するCSRF攻撃を試みました。
この攻撃は、SameSite属性をLaxに設定しておいたおかげで未然に防げました。eve.comはalice.mypaas.comと異なるSiteなので、eve.com経由のリクエストはCookieを送信できないからです。
eve.com経由のCSRFに失敗したEveはeve.mypaas.comでサイトを公開し、再びalice.mypaas.comに対する攻撃を試みました。
alice.mypaas.comはこの攻撃を防げません。
eve.mypaas.comとalice.mypaas.comは別オリジンではあるものの、同一サイトだからです。
このように、サブドメインを利用したCSRF2を想定すると、SameSite cookiesを設定するだけでは対策として不十分だといえます。
以上の例はPaaSを展開するというかなり特殊な状況ですが、そうでなくともSubdomain takeover攻撃などによりサブドメインが信頼できないという状況は考えられます。
じゃあどうするか
アプリケーション側で**Originリクエストヘッダー**を読み、同一オリジンからのリクエストであることを確認します。
参考
- https://developer.mozilla.org/ja/docs/Glossary/Origin
- https://developer.mozilla.org/ja/docs/Glossary/Site
- https://jub0bs.com/posts/2021-01-29-great-samesite-confusion/
-
Public Suffixの一覧はMozillaが管理しており、https://publicsuffix.org/で確認できます ↩
-
厳密にはCORFと呼ぶべきな気もしますが、手法としてはCSRFです ↩