概要
-
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:80 http://example.com
|
http://foo.example.com http://bar.example.com
|
http://foo.github.io http://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です ↩