@ledsun blog

無味の味は佳境に入らざればすなわち知れず

SameSite cookieについての勉強メモ

発端

Google Chromeの開発コンソールを有効にして、Webアプリケーションを開発しているときに次のような警告メッセージが表示されました。 これは一体どういう意味で、何に注意すればいいのでしょうか?

f:id:ledsun:20191202095526p:plain
Google Chromeの表示する警告

A cookie associated with a cross-site resource at http://pubannotation.org/ was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

Cookies default to SameSite=Lax - Chrome Platform Status を見ろと書いてあるので、みてみましょう。

Cookies default to SameSite=Lax

Treat cookies as SameSite=Lax by default if no SameSite attribute is specified.

CookiesをデフォルトでSameSite=Laxとして扱うと書いてあります。 SameSite=Lax とは何でしょうか?

SameSite=Lax

SameSite=Laxを検索するとCross-Site Request Forgery is dead!で紹介されています。 CSRF対策のようです。

日本語の解説もあります。

CSRF

対策したい問題がわからないと、対応策も理解できません。 CSRFはどのような攻撃でしたっけ?

安全なウェブサイトの作り方:IPA 独立行政法人 情報処理推進機構にあるPDF資料「安全なウェブサイトの作り方」のP30に「CSRF(クロスサイト・リクエスト・フォージェリ)」の解説があります。

あるサイトAへのログイン状態を維持したまま、悪意あるサイトB上のサイトAへのリンクをクリックした際に、サイトAがログインしたユーザーから意図したの操作だと誤認してしまう問題です。

よくある対応は、次のようなものです

  1. 変更が必要な処理はHTTPリクエストのメソッドをPOSTにする
  2. フォーム上にテンポラリーなトークンをhiddenパラメーターとして埋め込んでおく
  3. サーバーはHTTPリクエストに有効なトークンが含まれているか検証する

これによりユーザーのリクエストが、正規のフォームからのものであることが確認できます。

ふたたびSameSite=Lax

既知の対応策があるにも関わらずSameSite=Laxが道入されるのはなぜでしょうか? Cross-Site Request Forgery is dead! にProblemという章があります。

The trouble is though that these both put some kind of requirement on the site to implement and maintain the solution.

訳せば

問題は、これらの両方がソリューションを実装および維持するためにサイトに何らかの要件を課すことです。

そりゃまあ、Webサイト構築時に何らかの工夫をするよりは、ブラウザが対応してくれた方が嬉しいですよね。 で、具体的にはどのように使えばよいのでしょうか?

SameSite属性は次のように書きます。

Set-Cookie: sess=abc123; path=/; SameSite=lax

SameSite属性には次の2つの値があります。

  • Strict
  • LaxSameSite

SameSite=Strict

SameSite=Strict モードでは、オリジンが異なるサイトにクッキーを一切送信しません。他のサイトにあるリンクをクリックして対象の遷移してきた場合でも、送信しません。 つまり、ユーザーがログイン済みでも、クッキーを送信しないので、再度ログインを要求します。

このモードは、AmazonFacebookのように、認証クッキーが次の2段階に分かれているサイトでつかうことを想定しています。

  • ログイン用のクッキー
  • 決済や情報更新用のクッキー

後者のクッキーを SameSite=Strict モードにすることで、CSRF攻撃を確実に防ぎます。

SameSite=Lax

SameSite=Laxモードでは、 GET, HEAD, OPTIONS and TRACE メソッドのときはクッキーを送ります。 ログイン済みのユーザが、他サイトのリンクをクリックして遷移してきた場合は、クッキーが送信されるので、サーバーはログイン済みとして扱います。

この場合、サイトは変更を行うリクエストにはPOSTメソッドをつかうように実装します。 POSTメソッドをつかっている限り、CSRF攻撃を防ぎます。

Chromeの出す警告の意味

以上の知識を踏まえて、Chromeの警告の意味を考えてみましょう。

A cookie associated with a cross-site resource at http://pubannotation.org/ was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

翻訳すると

http://pubannotation.org/のクロスサイトリソースに関連付けられたCookieは、 SameSite属性なしで設定されました。 Chromeの今後のリリースでは、「SameSite = None」と「Secure」が設定されている場合にのみ、クロスサイトリクエストでCookieを配信します。開発者ツールのCookieを[アプリケーション]> [ストレージ]> [Cookies]で確認し、https://www.chromestatus.com/feature/5088147346030592およびhttps://www.chromestatus.com/feature/5633521622188032で詳細を確認できます。

この警告がでている時、ブラウザはXMLHttpRequestを使って自サイト以外のサイト(http://pubannotation.org/)からデータを取得しています。 このリクエストに対して、「クロスサイトリソースに関連付けられたCookie」と言っています。 特に、Chrome 80からは明示的に SameSite=NoneSecure が設定されていないクッキーはクロスオリジンのサイトには送信しなくなるという警告です。

このアプリケーションの用途ではクッキーを送信する必要はありません。 しかし http://pubannotation.org/ へのHTTPリクエストのレスポンスには Set-Cookieヘッダーがついています。 それで、Google Chromeは親切に教えてくれました。

Secure フラグ

ついでに警告に一緒に出ているSecureフラグはTough Cookies によると、次の形式で指定します。

Set-Cookie: sess=123; path=/; Secure

その意味は

The Secure flag is another optional flag that can be included in a Set-Cookie header that instructs the browser that the cookie must only ever be sent over a secure connection.

翻訳すると

ブラウザはセキュア(https)でない接続ではクッキーの情報を送りません。

蛇足

Cookiesの仕様、クソむずい・・・

https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-5.3 を見れば網羅できるのでしょうか?