SameSite Cookie について

クロスサイト Cookie を明示的にマークする方法を学ぶことで、サイトを保護します。

各 Cookie には Key-Value ペアと、その Cookie をいつ、どこで使用するかを制御する属性が含まれます。

SameSite 属性(RFC6265bis で定義)を導入すると、Cookie をファーストパーティ コンテキストと同一サイト コンテキストのどちらに制限するかを宣言できます。ここでの「サイト」の意味を正確に理解しておくと役に立ちます。 サイトとは、ドメイン サフィックスとその直前のドメイン部分を組み合わせたものです。たとえば、www.web.dev ドメインは web.dev サイトの一部です。

これは公開サフィックス リストで定義されるため、.com などのトップレベル ドメインだけでなく、github.io などのサービスも含まれます。これにより、your-project.github.iomy-project.github.io を別々のサイトとしてカウントできるようになります。

Cookie に SameSite 属性を導入すると、この動作を 3 つの方法で制御できます。属性を指定しないか、Strict または Lax を使用して Cookie を同一サイト リクエストに制限できます。

SameSiteStrict に設定すると、Cookie はファーストパーティ コンテキストでのみ送信されます。ユーザーが使用すると、Cookie のサイトとブラウザの URL バーに表示されているサイトが一致する場合にのみ Cookie が送信されます。たとえば、promo_shown Cookie が次のように設定されているとします。

Set-Cookie: promo_shown=1; SameSite=Strict

ユーザーがサイトにアクセスすると、リクエストとともに Cookie が想定どおりに送信されます。ただし、別のサイトからのリンクや友だちからのメールなどでサイトへのリンクをクリックした場合は、最初のリクエストで Cookie は送信されません。これは、パスワードの変更や購入など、常に最初のナビゲーションで実行される機能に関連する Cookie があるが、promo_shown には制限が厳しすぎる場合に便利です。読者がリンクをクリックしてサイトにアクセスした場合、設定を適用できるように Cookie を送信する必要があります。

そこで役立つのが SameSite=Lax です。これらのトップレベル ナビゲーションで Cookie を送信できるようにします。別のサイトがあなたのコンテンツを参照している 猫の記事の例をもう一度見てみましょうユーザーの猫の写真を直接使用して、元の記事へのリンクを提供します。

<p>Look at this amazing cat!</p>
<img src="https://blog.example/blog/img/amazing-cat.png" />
<p>Read the <a href="https://blog.example/blog/cat.html">article</a>.</p>

Cookie は次のように設定されています。

Set-Cookie: promo_shown=1; SameSite=Lax

読者が他のユーザーのブログを閲覧している場合、ブラウザが amazing-cat.png をリクエストしても Cookie は送信されません。ただし、読者がブログの cat.html へのリンクをたどると、そのリクエストに Cookie が含まれます。そのため、サイトの表示に影響する Cookie には Lax が適しています。ユーザーの操作に関連する Cookie には Strict が役立ちます。

最後に、値を指定しないという方法もあります。これまでは、すべてのコンテキストで Cookie を送信するよう暗黙的に指示していました。RFC6265bis の最新ドラフトでは、新しい値 SameSite=None を導入することで、このことが明示されています。つまり、None を使用すると、サードパーティのコンテキストで Cookie を意図的に送信したいということを明確に伝えられます。

コンテキストに応じて「なし」、「Lax」、「厳格」とラベル付けされた 3 つの Cookie
Cookie のコンテキストを NoneLaxStrict のいずれかとして明示的にマークします。

SameSite を使用しない場合のデフォルトの動作の変更

SameSite 属性は広くサポートされていますが、残念ながらデベロッパーには広く採用されていません。すべての場所に Cookie を送信するというオープンなデフォルト設定により、すべてのユースケースが機能しますが、ユーザーは CSRF や意図しない情報漏洩に対して脆弱になります。デベロッパーが自身の意図を表明し、より安全なエクスペリエンスを提供できるように、IETF の提案である Incrementally Better Cookie では、次の 2 つの重要な変更点が示されています。

  • SameSite 属性のない Cookie は SameSite=Lax として扱われます。
  • SameSite=None を使用する Cookie では、Secure も指定する必要があります。つまり、安全なコンテキストが必要です。

Chrome では、バージョン 84 でこのデフォルトの動作が実装されています。 Firefox では、Firefox 69 以降でテストすることができ、将来的にはデフォルトの動作になる予定です。Firefox でこれらの動作をテストするには、about:config を開き、network.cookie.sameSite.laxByDefault を設定します。Edge でもデフォルトの動作を変更する予定です。

デフォルトは SameSite=Lax

属性が設定されていません
Set-Cookie: promo_shown=1

SameSite 属性を指定せずに Cookie を送信すると...

デフォルトの動作を適用しました
Set-Cookie: promo_shown=1; SameSite=Lax

ブラウザでは、SameSite=Lax が指定されているかのように Cookie が処理されます。

これはより安全なデフォルトを適用することを目的としていますが、ブラウザに依存して適用するのではなく、明示的な SameSite 属性を設定することが理想的です。これにより、Cookie の意図が明示され、ブラウザ間で一貫したエクスペリエンスが得られる可能性が高まります。

SameSite=None は安全である必要があります

不承認
Set-Cookie: widget_session=abc123; SameSite=None

Secure を指定せずに Cookie を設定すると拒否されます

承認
Set-Cookie: widget_session=abc123; SameSite=None; Secure

SameSite=NoneSecure 属性と必ずペアリングしてください。

この動作をテストするには、Chrome 76 以降で about://flags/#cookies-without-same-site-must-be-secure を有効にします。Firefox 69 以降の場合は、about:confignetwork.cookie.sameSite.noneRequiresSecure を設定します。

新しい Cookie を設定するときにこれを適用し、有効期限が近づいていても既存の Cookie を積極的に更新することをおすすめします。

どちらの変更も、以前のバージョンの SameSite 属性を正しく実装しているか、まったくサポートしていないブラウザとの下位互換性があります。これらの変更を Cookie に適用することで、ブラウザのデフォルトの動作に依存せずに、本来の用途を明示的に指定できます。同様に、まだ SameSite=None を認識していないクライアントも、この属性を無視して、属性が設定されていないかのように処理を続行する必要があります。

SameSite=None の変更とブラウザの動作の違いに適切に対応するために Cookie を更新する方法について詳しくは、フォローアップ記事 SameSite Cookie のレシピをご覧ください。

Lily Chen、Malte Ubl、Mike West、Rob Dodson、Tom Steiner、Vivek Sekhar の協力とフィードバックに感謝します。

Cookie のヒーロー画像(作成者: Pille-Riin PriskeUnsplash