CookieのSameSite属性とは
cookieの適用スコープを明示的に宣言する
2019年11月22日
著者: 竹洞 陽一郎
SameSite属性とは
CookieのSameSite属性とは、Cookieが利用できるドメインのスコープを明示的に示すものです。
その仕様は、2016年4月6日にドラフトとして"Same-site Cookies draft-west-first-party-cookies-07"として、インターネット技術の標準化を推進するIETF(Internet Engineering Task Force)にGoogleから提示されています。
The "SameSite" attribute limits the scope of the cookie such that it will only be attached to requests if those requests are "same-site", as defined by the algorithm in Section 2.1.
For example, requests for "https://example.com/sekrit-image" will attach same-site cookies if and only if initiated from a context whose "site for cookies" is "example.com".If the "SameSite" attribute's value is "Strict", or if the value is invalid, the cookie will only be sent along with "same-site" requests.
If the value is "Lax", the cookie will be sent with "same-site" requests, and with "cross-site" top-level navigations, as described in Section 4.1.1.SameSite属性は、Cookieのスコープを、それらのリクエストがセクション2.1のアルゴリズムによって定義されるようにsame-siteである場合にのみ、リクエストに付加されるように制限します。
例えば、「https://example.com/sekrit-image」のリクエストは、「Cookieのサイト」が「example.com」であるコンテキストから開始された場合にのみ、same-site Cookieを添付します。SameSite属性の値がStrictの場合、または無効な値の場合、Cookieはsame-siteのリクエストにのみ送信されます。
値がLaxの場合、セクション4.1.1で説明しているように、Cookieはsame-siteのリクエストと、cross-siteのトップレベルナビゲーションに送信されます。
| SameSiteの値 | 意味 | ドメインのスコープ |
|---|---|---|
| Strict | 厳格 | same-siteのリクエストにのみ付与される |
| Lax | 緩い | same-siteのリクエストと、cross-siteのトップレベルナビゲーションに付与される |
| None | 指定無し | スコープの指定がない。cross-site配信で使う。 |
2019年5月7日の追加
2019年5月7日、"Incrementally Better Cookies draft-west-cookie-incrementalism-00"として、2箇所変更する案をGoogleがIETFに提示しています。
以下の2点が追加されました。
-
明示的なSameSite属性がない場合は、"SameSite=Lax"として扱います。つまり、"Set-Cookie"の"key=value"は、"SameSite=Lax"と同等のcookieを生成します。
cross-site配信を必要とするCookieは、Cookieの作成時に"SameSite=None"を設定することによって、そのような動作を明示的に選択できます。 -
"SameSite=None"を選択した場合は、CookieにSecure属性を設定する必要があります。
(概念的に"__Secure-"プレフィックスの動作に似ています)
つまり、"Set-Cookie"の"SameSite=None;Secure"は受け入れられますが、"SameSite=None"は拒否されます。
SameSite判定アルゴリズム
SameSiteであるか、CrossSiteであるかは、以下のアルゴリズムで判断されます。
- クライアントのリクエストがnullの場合は、same-siteを返します。
- siteに、cookieをリクエストしたクライアントのサイトを設定します。
- targetに、リクエストした現在のURLの登録可能なドメインを設定します。
- もしsiteとtargetが一致したら、same-siteを返します。
- そうでなければ、cross-siteを返します。
Documentベースのリクエスト
The URI displayed in a user agent's address bar is the only security context directly exposed to users, and therefore the only signal users can reasonably rely upon to determine whether or not they trust a particular website.
The registrable domain of that URI's origin represents the context in which a user most likely believes themselves to be interacting.
We'll label this domain the "top-level site".ユーザエージェントのアドレスバーに表示されるURIは、ユーザに直接公開される唯一のセキュリティコンテキストであり、したがって、ユーザが特定のWebサイトを信頼しているかどうかを判断するために合理的に信頼できる唯一のシグナルです。
そのURIの起点の登録可能なドメインは、ユーザが自分が対話していると信じている可能性が最も高いコンテキストを表します。
このドメインには「トップレベルサイト」というラベルを付けます。
For a document displayed in a top-level browsing context, we can stop here: the document's "site for cookies" is the top-level site.
For documents which are displayed in nested browsing contexts, we need to audit the origins of each of a document's ancestor browsing contexts' active documents in order to account for the "multiple-nested scenarios" described in Section 4 of RFC7034.
These document's "site for cookies" is the top-level site if and only if the document and each of its ancestor documents' origins have the same registrable domain as the top-level site.
Otherwise its "site for cookies" is the empty string.最上位レベルの閲覧コンテキストで表示されるドキュメントの場合は、ここで終わります。ドキュメントの「Cookieのサイト」は最上位レベルのサイトです。
ネストされた閲覧コンテキストで表示されるドキュメントの場合、RFC7034のセクション4で説明されている「複数のネストされたシナリオ」について、各ドキュメントの祖先ブラウジングコンテキストのアクティブなドキュメントの出所を監査する必要があります。
これらのドキュメントの「Cookieのサイト」は、ドキュメントとその各祖先ドキュメントの出所が最上位サイトと同じ登録可能ドメインを持つ場合に限り、最上位サイトです。
それ以外の場合、「Cookieのサイト」は空の文字列です。
RFC7034は、X-Frame-Optionヘッダを定めたものです。
これは、<frame>、<iframe>、<embed>、<object>をドキュメント内で表示を許可するかどうかを示すために使われます。
セクション4は以下のように記載されています。
The introduction of the X-Frame-Options HTTP header field improves the protection against clickjacking.
However, it is not self-sufficient enough to protect against all kinds of these attack vectors.
It must be used in conjunction with other security measures like secure coding (e.g., input validation, output encoding, etc.) and the Content Security Policy version 1.0 [CSP].X-Frame-Options HTTPヘッダーフィールドの導入は、クリックジャッキングに対する保護を改善します。
しかし、あらゆる攻撃を防ぐには、これだけでは十分ではありません。
セキュアコーディング(例えば、入力検証、出力符号化など)、コンテンツセキュリティポリシーのバージョン1.0(CSP)など、他のセキュリティ対策と組み合わせて使用する必要があります。
ちなみにCSPは、Version1からVersion2へと移行しています。
トップレベル判断のアルゴリズム
- top-documentをdocumentのブラウジングコンテキストのトップレベルのアクティブなドキュメントに設定します。
- top-documentのサンドボックスされたオリジンブラウズコンテキストフラグが設定されている場合はtop-originをtop-documentのURIのオリジンとし、それ以外の場合はtop-documentのオリジンとします。
- documentsを、documentと、documentの祖先がブラウズしていたコンテキストのアクティブな各ドキュメントを含むリストにします。
- documentsのitemごとに次の手順を実行します。
- itemのサンドボックスされたオリジンブラウジングコンテキストフラグが設定されていた場合は、itemのURIのオリジンをoriginとし、それ以外の場合はitemのオリジンをoriginと設定します。
- もしoriginのホストの登録可能なドメインが、top-originのホストの登録可能なドメインと完全に一致しない場合は、空文字を返します。
- top-siteを返します。
Workerベースのリクエスト
Workerには、三つの種類があります。
| 分類 | 中分類 | 処理 | 動作におけるドキュメントとの関係 | スコープ |
|---|---|---|---|---|
| Web Worker | Dedicated Worker | フォアグランドプロセスの別スレッド | 連動 | 呼出し元ドキュメントのみ |
| Shared Worker | 呼出し元以外の複数のドキュメントやiframe、Worker | |||
| Service Worker | バックグラウンドプロセス | 完全独立 | スコープで定義したドキュメント、iframe、Shared Worker | |
Worker-driven requests aren't as clear-cut as document-driven requests, as there isn't a clear link between a top-level browsing context and a worker.
This is especially true for Service Workers, which may execute code in the background, without any document visible at all.Note: The descriptions below assume that workers must be same-origin with the documents that instantiate them.
If this invariant changes, we'll need to take the worker's script's URI into account when determining their status.トップレベルのブラウジング・コンテキストとWorkerとの間に明確なリンクがないため、Worker駆動のリクエストはDocument駆動のリクエストほど明確ではありません。
これは特に、ドキュメントを全く表示せずにバックグラウンドでコードを実行するService Workersに当てはまります。注意:以下の説明では、Workerはそれらをインスタンス化するドキュメントとsame-originである必要があると想定しています。
この不変条件が変更された場合には、Workerのスクリプトの状況を判断する際にWorkerのスクリプトのURIを考慮する必要があります。
Dedicated Worker/Shared Workerの場合
ドキュメントと連動してJavaScriptの処理を別スレッドで稼働させるWeb Workerについては、以下のように書かれています。
Dedicated workers are simple, as each dedicated worker is bound to one and only one document.
Requests generated from a dedicated worker (via "importScripts", "XMLHttpRequest", "fetch()", etc) define their "site for cookies" as that document's "site for cookies".Shared workers may be bound to multiple documents at once.
As it is quite possible for those documents to have distinct "site for cookie" values, the worker's "site for cookies" will be the empty string in cases where the values diverge, and the shared value in cases where the values agree.Dedicated Workerはシンプルで、各Dedicated Workerは1つのドキュメントにのみバインドされるためです。
(importScripts、XMLHttpRequest、fetch()などによって)Dedicated Workerから生成されたリクエストから生成された依頼は、それらの「Cookieのサイト」をそのドキュメントの「Cookieのサイト」として定義します。Shared Workerは、一度に複数のドキュメントにバインドできます。
これらの文書が異なる「Cookieのサイト」値を持つことは十分に可能なので、このWorkerの「Cookieのサイト」は、値が異なる場合は空の文字列になり、値が一致する場合は共有の値になります。
WorkerGlobalScope判断のアルゴリズム
WorkerGlobalScope(「worker」)が渡されると、以下のアルゴリズムによって「Cookieのサイト」(登録可能なドメインか空の文字列)が返されます。
- siteをworkerのオリジンホストの登録可能なドメインにします。
- workerのドキュメント内の各documentについて、次の操作を行います。
- document-siteをdocumentのsite for cookies(セクション2.1.1に定義)とします。
- document-siteがsiteと完全に一致しない場合は、空の文字列を返します。
- siteを返します。
Service Workersの場合
PWA (Progressive Web Application)で使われる、ドキュメントとは完全独立でバックエンドプロセスとして稼働するService Workerについては、以下のように書かれています。
Service Workers are more complicated, as they act as a completely separate execution context with only tangential relationship to the Document which registered them.
Requests which simply pass through a service worker will be handled as described above: the request's client will be the Document or Worker which initiated the request, and its "site for cookies" will be those defined in Section 2.1.1 and Section 2.1.2.1 Requests which are initiated by the Service Worker itself (via a direct call to "fetch()", for instance), on the other hand, will have a client which is a ServiceWorkerGlobalScope.
Its "site for cookies" will be the registrable domain of the Service Worker's URI.Service Workersは、登録されたドキュメントとの接線関係のみを持つ、完全に独立した実行コンテキストとして機能するため、より複雑になります。
Service Workerを単に通したリクエストは、上述したとおり、リクエストのクライアントは、リクエストを開始したドキュメントまたはWorkerになり、その「Cookieのサイト」は、セクション2.1 .1およびセクション2.1.2.1で定義されている要求であり、Service Worker自身が開始したリクエスト(例えば、fetch()の直接呼出し)は、ServiceWorkerGlobalScopeであるクライアントを持ちます。
その「Cookieのサイト」は、Service WorkerのURIの登録可能なドメインになります。
ServiceWorkerGlobalScope判断のアルゴリズム
ServiceWorkerGlobalScope(「Worker」)が渡されると、以下のアルゴリズムは「Cookieのサイト」(登録可能なドメインか空の文字列)が返されます。
- workerのオリジンホストの登録可能なドメインを返します。
Chrome 80からの適用
2020年1月もしくは2月にリリースされると目されているChrome 80では、このSameSite属性が必須となります。
| ドキュメントのトップレベル | 選択できる値 |
|---|---|
| 自社のドメイン | Strict Lax |
| サードパーティのドメイン | None |
もしも、SameSiteの属性が設定されていない場合には、Laxと見做されて扱われます。
そして、サードパーティー系のものについては、"SameSite=None;Secure"にしないと、Chromeによってリジェクトされます。
自社サイトに色々と組み込んでいるサードパーティーサービスについて、この対応が済んでいるかどうか、確認する必要があります。
ITP(Intelligent Tracking Prevention)の対応
Chromeだけに対応すれば良いというわけではありません。
iPhoneユーザやMacユーザが利用するSafariも考慮する必要があります。
ITP2.2での変更点
ます、トラッカー認定とそのCookieの寿命が1日になる件は、ITP2.2での導入です。
その条件は、以下のように書かれています。
As of ITP 2.2, persistent cookies set through document.cookie are capped to one day of storage when both of the following conditions are met:
- A domain classified with cross-site tracking capabilities was responsible for navigating the user to the current webpage.
- The final URL of the navigation mentioned above has a query string and/or a fragment identifier.
ITP2.2では、以下の条件に適合した場合に、document.cookieによって入ったpersistent cookieの寿命をストレージでの1日に制限します。
- cross-siteトラッキングの能力を持つと分類されたドメインによってユーザが現在のWebページへとナビゲートされた
- 上述された最終URLへのナビゲーションに、Query Stringやfragment identifierが付いていた
ここで書かれているとおり、Trackerとして分類されるかどうかは、cross-site trackingを行っているドメインかどうかです。
ここで、SameSite属性が重要となります。
"SameSite=Strict"と設定することで、自社のドメインで付与されたcookieは、自社のWebサイトでしか使わない、他のドメインでは使われないという事を保証します。
これによって、自社ドメインはTrackerではないという事を担保します。
ファーストパーティーのCookieがTrackerとして認定されるケースについては、What Is Intelligent Tracking Prevention and How Does It Work? [versions 1.0 – 2.3]の解説が分かりやすいです。
ITP2.3での変更点
ITP2.3での以下の事項が追加されています。
Since ITP 2.2, several trackers have announced their move from first-party cookies to alternate first-party storage such as LocalStorage. ITP 2.3 counteracts this in the following way:
- website.example will be marked for non-cookie website data deletion if the user is navigated from a domain classified with cross-site tracking capabilities to a final URL with a query string and/or a fragment identifier, such as website.example?clickID=0123456789.
- After seven days of Safari use without the user interacting with a webpage on website.example, all of website.example’s non-cookie website data is deleted.
Together with ITP’s capped expiry of client-side cookies, this change removes trackers’ ability to use link decoration combined with long-term first-party website data storage to track users. Put differently, ITP 2.3 caps the lifetime of all script-writeable website data after a navigation with link decoration from a classified domain.
The reason why we cap the lifetime of script-writable storage is simple. Site owners have been convinced to deploy third-party scripts on their websites for years. Now those scripts are being repurposed to circumvent browsers’ protections against third-party tracking. By limiting the ability to use any script-writeable storage for cross-site tracking purposes, ITP 2.3 makes sure that third-party scripts cannot leverage the storage powers they have gained over all these websites.
ITP 2.2以降、幾つかのトラッカーがファーストパーティーのクッキーからLocalStorageのような代替ファーストパーティー・ストレージへの移行を発表しています。ITP2.3は、この問題を次のように解決します。
- サイトを乗り越えてトラッキングできる能力を持つと分類されたドメインから、website.example?clickID=0123456789のようなQuery Stringやフラグメント識別子が付いているリンクにナビゲートされて、website.exampleに移動した場合、non-cookie website data deletionのマークが付けられます。
- website.exampleのWebページをユーザが操作しないでSafariの使用が7日を経過したら、website.exampleのnon-cookie website dataは削除されます。
ITPがクライアント側のクッキーの有効期限を制限したことに合わせて、ユーザを追跡するための長期に亘るfirst-partyのWebサイトのデータストレージと組み合わせて、link decorationを使うトラッカーの能力を排除する変更となります。 言い換えれば、ITP 2.3は、サイトを乗り越えてトラッキングすると分類されたドメインから、link decorationでナビゲートされる場合、そのscript-writebleなWebサイトデータの寿命を制限するものです。
スクリプト書き込み可能ストレージの存続期間を制限する理由は単純です。サイト所有者は長年、自社のウェブサイトにサードパーティー製のスクリプトを導入するように説得されてきました。現在、これらのスクリプトは、サードパーティーの追跡に対するブラウザの保護を回避するために再利用されています。スクリプト書き込み可能なストレージをクロスサイト追跡の目的で使用する機能を制限することで、ITP 2.3は、サードパーティ製スクリプトがこれらすべてのWebサイトで得たストレージ能力を活用できないようにします。
「Cookieが使えないなら、LocalStorageを使おう」というリターゲティング広告の企業などが出てきたので、それに対処するためのアップデートです。
CNAMEでファーストパーティー化するのはご注意
最近、あるリターゲティング広告の企業が、このLocalStorageの制限を回避すべく、顧客のDNSのCNAMEを使って、ファーストパーティ化させて、リターゲティング広告企業のサーバから配信するように仕様変更しました。
これは、セキュリティの観点から危険です。
その会社は、「情報を抜き取ったりとかできませんから」と言ってますが、JavaScriptでフォームの情報を抜き取ることが可能です。
お客様のご依頼で、弊社で実証実験を行って結果を提出したのですが、それ以来、そのリターゲティング広告の企業からは全く返信がありません。
まとめ
- Chrome80から、CookieのSameSite属性がチェックされるようになり、明示的なSameSite属性がない場合は、自社サイトのCookieについて"SameSite=Lax"として扱われます。
- 「じゃぁ、とりあえず、設定してなくてもいいよね」と思うと間違いで、AppleのITP2.3の仕様により、SafariではTrackerとして扱われる可能性が大きいので、"SameSite=Strict"として、自社のCookieのスコープを明示化すべきでしょう。
- SafariでTrackerとして認定されると、Cookieの寿命が1日になるので、お客様の顧客体験上、不便になります。
- サードパーティーのサービスについては、各事業者は、"SameSite=None;Secure"にしなくてはいけません。そうしないと、2020年2月にリリース予定のChrome80以降でリジェクトされます。
- サードパーティーのCookieの寿命は、Safariにおいては、ITP2.2によって1日となっています。Cookieが1日の寿命になった事に対するそのサービスへの影響について、事業者に説明を求めたり、確認する必要があるでしょう。
- サードパーティーの事業者は、このITP2.2の仕様を回避するため、Cookieの代わりにLocalStorageを使うようになりましたが、ITP2.3から、Cookieと同じく、SafariでのサードパーティのLocalStorageのデータの寿命は1日となりました。
- サードパーティーの事業者は、ITP2.3の仕様を回避するため、DNSのCNAMEを使ってファーストパーティー化を顧客に提案していますが、情報漏洩の危険があるという事は認識しましょう。フォームへの入力情報をJavaScriptで抜くことが技術的に可能です。