Featured image of post Cookies - SameSite Attribute

Cookies - SameSite Attribute

Cookies - SameSite Attribute

Photo by Mohammad Rahmani on Unsplash

Chromeはバージョン84からCookieのSameSite属性のデフォルトをLaxにしました。Third-party cookiesを使用するサービスでSameSiteを設定していない場合は影響を受ける可能性があります。

概要

CookieはWebサービスにおいて状態を保存するための仕組みで、ログイン状態の維持、ショッピングカート、広告トラッキングなどによく使用されます。しかし、Cookieの広範な使用に伴い、プライバシーやセキュリティの懸念も生じており、それらの問題を解決するためにSameSiteが登場しました。

 

First-Party and Third-Party

Cookieのソース(Set-Cookie)に基づいて、各Cookieには固有のドメインがあります。ユーザーのブラウザの現在のURLを見て、Cookieのドメインが現在のURLと一致する場合はFirst-Party、そうでない場合はThird-Partyとなります。

Third-party

例えば、a.comを閲覧しているときにthird-party.comへリクエストを送信し、third-party.comからCookieを受け取ったとします。ブラウザはリクエスト時に同じドメインのCookieを自動的に含めるため、その後b.comのような他のサイトを閲覧した際にthird-party.comへリクエストが送信されると、サーバーはCookieを受け取ります。これら2つのサイトにとって、third-party.comのCookieはThird-partyとなります。

First-party

もしthird-party.comドメインに一致するWebサイトを閲覧した場合もCookieが送信されます。この場合、このCookieはFirst-partyと呼ばれます。

 

Same-Origin and Same-Site

先ほどの例ではドメインが一致するかどうかでCookieの種類を判定していましたが、より正確にはSiteが同じかどうかで判定すべきです。これはよく見かけるSame-originと関係があるのでしょうか?

Cookies SameSite

Origin

OriginはScheme、Host、Portで構成されます。判定方法は非常にシンプルで、2つのURLのScheme、Host、Portがすべて同じであればSame-origin、そうでなければCross-originです。

Site

Same-Siteの判定にはEffective top-level domains(eTLDs)が関わってきます。すべてのeTLDsはPublic Suffix Listで定義されており、SiteはeTLDにプレフィックスを加えたもので構成されます。

例えば: github.ioはPublic Suffix Listに存在します。これにプレフィックス(例:a.github.io)を加えるとSiteになります。したがって、a.github.iob.github.ioは2つの異なるSite(Cross-site)です。

example.comはPublic Suffix Listに存在しませんが、.comは存在するため、example.comはSiteであり、a.example.comb.example.comは同じSite(Same-site)となります。

SiteにはPortが含まれないため、Portが異なっていてもSame-siteになることに注意してください。

 

Why SameSite?

「リクエストには必ずそのドメインのCookieを含める」という仕組みは、同時にセキュリティやその他の問題をもたらしました。その中で最も重要なのがCross-site request forgery(CSRF)です。

CSRF

ユーザーがexample.comにログインしてCookieを取得したと仮定します。ユーザーが悪意のあるサイトevil.comを閲覧すると、そのサイト内のJavaScriptがexample.com/pay?amount=1000に対してPOSTリクエストを送信する可能性があります。ブラウザは自動的にexample.comのCookieを含めるため、ユーザーは知らないうちに1000ドルを支払ってしまうことになります。サーバーはこのリクエストがどこから来たのかを判断できません。

制限

Cookie自体にはFirst-party環境でのみ送信するように設定する機能がないため、リクエストはどのような環境でもCookieを含んでしまいます。サーバーはリクエストの送信元を識別できず、通常通り応答するしかありません。同時に、クライアントは無駄なCookieを送信して帯域を浪費することになります。

解決策

SameSite属性があれば、異なる環境でのCookieの送信条件を個別に設定できます。

SameSite

SameSite属性には3つの値があります。StrictまたはLaxに設定すると、Same-SiteリクエストでのみCookieを含めるように制限できます。空欄のままにした場合の動作はブラウザによって異なりますが、Chromeの場合はデフォルトでLaxです。

Strict

First-party環境でのみCookieを含めます。しかし、これには問題があります。例えば、ユーザーがexample.comでFacebookの投稿リンク(fb.comと仮定)を見たとします。ユーザーがfb.comにログインしてCookieを持っていたとしても、リンクをクリックした後、2つのサイトはCross-siteであるためCookieは送信されず、ログインページが表示されるだけになります。

そのため、Strict投稿の削除や支払いなどの操作に適しています。

Lax

Strictの厳しすぎる制限を解決するために、Laxは以下の場合、Cross-siteであってもCookieを送信します

  • アドレスバーへのURL入力
  • リンク<a href="...">のクリック
  • フォーム<form method="GET">の送信
  • プリレンダリング<link rel="prerender" href="...">

これらの状況には2つの共通点があります。すべてGETリクエストであり、トップレベルナビゲーション(Top-level Navigation)をトリガーすることです。これにより、Strictのように毎回再ログインが必要になる問題を回避しつつ、他のWebサイトを閲覧しているときに知らないうちにCookieを送信してしまうことも防げます。

Lax + POST

しかし、既存の一部のログインフローを壊さないように、Chromeは現在SameSite=Laxの制限を少し緩和し、開発者に猶予を与えています。

Cookieが設定されてから2分以内であれば、リクエストメソッドに関係なく、トップレベルのページ遷移をトリガーする限りCookieが送信されます。つまり、フォーム送信<form method="POST">などでブラウザがページを移動する場合です。

詳細はLax + POSTに関するスレッドをご覧ください。

None

Third-party cookieを送信したい場合は、SameSite=None; Secureを設定する必要があります。そうです、これからはテスト環境でThird-party cookieを送信したい場合は、https://localhostを準備してください。

また、XHR/FetchCross-Origin Requestを送信する場合、Cookieを含め、レスポンスヘッダーのSet-Cookieを有効にするには、別途withCredentials: trueを設定する必要があります。そしてサーバー側はレスポンスヘッダーにAccess-Control-Allow-Credentials: trueを設定しなければ、JavaScriptはレスポンスの内容にアクセスできません。

非対応ブラウザ

すべてのブラウザが最新のSameSiteルールに対応しているわけではないため、サーバー側でいくつかの一時的な回避策(Workaround)を追加して、複数のブラウザをサポートすることができます:

両方のCookieを設定する

この方法はほぼすべてのブラウザの問題を解決できますが、欠点はCookieが2つになることです:

Set-cookie: name=value; SameSite=None; Secure
Set-cookie: name-legacy=value; Secure

サーバー側のコード:

if (req.cookies['name']) {
  // 新しいものがあれば新しいものを使う
  cookieVal = req.cookies['name'];
} else if (req.cookies['name-legacy']) {
  // なければ古いものを使う
  cookieVal = req.cookies['name-legacy'];
}

User Agent

リクエストのUser agentからブラウザを判断してSet-Cookieの内容を決定します。この方法はCookieを設定するコードを修正するだけで済み、パース部分を変更する必要はありませんが、この判定方法は変数が多く、誤ったCookieを設定してしまう可能性が高くなります。

 

振り返り

  • SameSite属性が設定されていないCookieはSameSite=Laxとなり、Cross-site環境では送信できません
  • Cross-siteでCookieを送信したい場合は、SameSite=None; Secureを設定する必要があります。
  • SameSite sandboxを使用して、現在使用しているブラウザが最新のSameSiteルールに準拠しているかどうかをテストできます。

Reference

All rights reserved,未經允許不得隨意轉載
Built with Hugo
テーマ StackJimmy によって設計されています。