SameSite Cookie について

クロスサイト Cookie を明示的にマークする方法を確認して、サイトを保護しましょう。

Rowan Merewood 氏
Rowan Merewood

各 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 を送信できるようにすることです。先ほど、別のサイトがコンテンツを参照している cat 記事の例をもう一度見てみましょう。あなたの猫の写真を直接利用し、元の記事へのリンクを提供します。

<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 を意図的に送信したいということを明確に伝えられます。

コンテキストに応じて None、Lax、Strict のラベルが付いた 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

ブラウザでは、その Cookie は SameSite=Lax が指定されているものとして扱われます。

これはより安全なデフォルトを適用することを目的としていますが、ブラウザに依存して適用するのではなく、明示的な 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 を認識していないクライアントも、この属性を無視して、この属性が設定されていないものとして処理を続行する必要があります。

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

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

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