最近、Go言語で個人開発をやっていてCookieでつまづいたことで、Cookieに対する理解度の低さを改めて感じたので少し調べていきます。
執筆前の僕のCookieの認識は「ブラウザで保存されるデータで、http通信で送信されてログインとかに利用されるやつ」なので、間違っていたら教えてください。
定義
Cloudflareの定義によると「Cookieとは、Webサーバーが生成してWebブラウザーに送信する小さな情報ファイルです。Webブラウザは、受け取ったCookieを所定の期間、またはWebサイト上にユーザーのセッションがある間保存します。また、ユーザーは次回以降Webサーバーにリクエストする際に、関連するCookieを添付します。」とのことです。なので、最初の認識で大体あっている。
Cookieを保存する流れ
サーバーが発行したJWTなどをCookieに保存する場合、サーバーはHTTPリクエストのヘッダに"Set-Cookie"というフィールドを含み、その中でkey=value;の形で保存して欲しいCookieを指定することができる。また、「;」の後には属性が続いていく。複数のCookieを設定する場合、それぞれのCookieに対して別々のSet-Cookieフィールドが含まれる。つまり、3種類のキーバリューを保存して欲しい場合はSet-Cookieフィールドを3つ指定する。
ちなみにGo言語で設定するならhttpライブラリを使ってこんな感じになる。
http.SetCookie(w, &http.Cookie{ Name: "jwt", Value: tokenString, Secure: true, HttpOnly: true, Path: "/", Expires: time.Now().Add(60 * 60 * 24 * time.Minute), SameSite: http.SameSiteNoneMode, })
一方で、クライアントがサーバーにリクエストを送る際には"Cookie"というフィールドにキーバリューを詰めて送る。ここで、キーバリューは「;」で分けられる。
属性
この属性がよくわからなかったので調べていく。属性次第ではSet-Cookieを指定してもWebブラウザに保存されなかったり。軽く紹介するだけなので、以下を見た方が多分良い。
Secure
HTTPSでのみ利用できるようにする。今時基本的にHTTPSなので指定しておいて損はない気がする。ローカルホストだと動かなくなるので注意。 (追記: ブラウザによってはlocalhostでのSecure属性は無視してくれるらしい。やってみるとchromeはそうっぽい。)
teratail.com
HttpOnly
この属性が指定されたクッキーはJavaScriptから読まれない。XSS攻撃の対策になる。JSで利用しないならtrueにしておいてよさそう。
Domain
Cookieを受信できるホストを指定する。指定しない場合はサーバと同じドメインをホストとし、サブドメインは除外される。指定した場合はサブドメインも含まれる。例えば、Domain=mozilla.org を設定すると、developer.mozilla.org のようなサブドメインも含まれる。
Path
この属性が指定されると、Pathに一致するページでのみリクエストにクッキーが含まれる。 "/"であれば全てのパスに一致するし、"/users"としたら"/message"には一致せず、クッキーは送信されない。
SameSite
SameSite属性では異なるサイト間でのリクエストでCookieを送るべきかそうでないかを指定できる。これは、CSRFに対しての防御となる。SameSiteの設定にはStrict, Lax, Noneの3種類がある。デフォルトはLax。
Strict ... 元サイトからのリクエストに対してのみCookieを送る。外部サイトからのリダイレクトを含む、他のサイトからのリクエストではCookieは送信されない。
Lax ... 元サイトに対してのみCookieを送るが、外部サイトからリンクを辿った場合にもCookieを送る
None ... 異なるサイト間でも送信できる(ただし、Secure属性を設定する必要がある。)
Expires および MaxAge
Cookieを残す期間を指定することができる。両方指定した場合はMaxAgeが優先される。ちなみに無期限にすることはできないらしい。