この記事では『CookieのSameSite属性』について、
- CookieのSameSite属性とは
- SameSite属性のStrictとLaxとNoneの違い
- SameSite属性のデフォルト値
- サンプルコードでSameSite属性の動作確認を行う
などを図やサンプルコードを用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。
CookieのSameSite属性とは
SameSite属性は、Cookie(クッキー)を発行する際に指定できる属性の1つで、別ドメインへのリクエスト時にCookieを送信するか否かを指定するものです。
例えば、WebブラウザにはサイトBのCookieが保存されているとします。その状態において、サイトAからサイトBにリンクなどを経由して遷移する時や、サイトAからサイトBへのPOSTリクエスト時などにブラウザに保存されているサイトBのCookieを送信するか否かをSameSite属性で決めることができます。
補足
SameSite属性はSame-site Cookies draft-west-first-party-cookies-07という仕様で新しく追加されました。
SameSite属性のStrictとLaxとNoneの違い
CookieのSameSite属性はStrict(厳しい)、Lax(緩い)、None(なし)の3つの値をとります。これらの値はこれはセキュリティレベルの高さをしており、Strictが一番セキュリティレベルが高いです。
SameSite属性はHTTPレスポンスのSet-Cookie
ヘッダでSameSite=Lax
のように指定することができます。SameSite属性はオプションであるため指定しなくてもよく、指定しない場合はブラウザ側のデフォルト設定(Chrome 80からはLax
)になります。
same-site
なリクエストについてはSameSite属性が何であろうとCookieは送信されます。SameSite属性によって挙動が変わるのはcross-site
なリクエストの時です。
- SameSite=None
cross-site
なリクエスト時、どのリクエストでもCookieを送信します。- Chrome 79以下でのデフォルト値です。
- セキュリティ上の理由から、Noneを設定するにはSecure属性(HTTPS接続必須)も同時に設定する必要があります。
- SameSite=Lax
- Strictより制限を緩和した設定値です。
- Chrome 80からのデフォルト値です。
cross-site
なリクエスト時、Cookieの送信条件が複雑で、「サイト間の遷移(トップレベルナビゲーション)」かつ「安全なメソッドによるリクエスト時」にのみCookieを送信します。具体例を以下に示します。- サイト間の遷移(トップレベルナビゲーション)時にはCookieを送信する
- サイトAからサイトBにリンクなどを経由してアクセスした際に、ブラウザに保存されているサイトBのCookieを送信します。
- 安全でないメソッドによるリクエスト時はCookieを送信しない
- サイトAからサイトBへのリクエストにおいて、安全でないHTTPメソッド(例えば、
POST
メソッド)によるリクエストでは、ブラウザに保存されているサイトBのCookieを送信しません。
- サイトAからサイトBへのリクエストにおいて、安全でないHTTPメソッド(例えば、
- トップレベルナビゲーションかつ安全なHTTPメソッドによるリクエスト時はCookieを送信する
- サイトAからサイトBへのリクエストにおいて、トップレベルナビゲーションかつ安全なHTTPメソッド(
GET
,HEAD
,OPTIONS
,TRACE
)によるリクエストであれば、ブラウザに保存されているサイトBのCookieを送信します。
- サイトAからサイトBへのリクエストにおいて、トップレベルナビゲーションかつ安全なHTTPメソッド(
- サイトをまたぐリソースの読み込み時にはCookieを送信しない
img
タグによる画像埋め込み、XHR(XMLHttpRequest)、iframe
タグなどによるサイトをまたぐリソースの読み込み時にはCookieを送信しません。
- サイト間の遷移(トップレベルナビゲーション)時にはCookieを送信する
same-siteとcross-siteの違い
続きを見るsame-site
とcross-site
の違いについては下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。 Same-site・Cross-site・Same-origin・Cross-originの違いについて!
トップレベルナビゲーションとは
Webブラウザのアドレスバーに表示されているURLの変更が伴う遷移のことをトップレベルナビゲーションといいます。
『トップレベルナビゲーション』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。 続きを見るトップレベルナビゲーション(Top-Level Navigation)とは?分かりやすく解説!
安全なメソッドとは
RFC 7231の4.2.1では、以下の4つのメソッドを安全なメソッド(Safe Methods)として定義しています。また、RFC 6265bisの5.3.7.1でも、RFC 7231の内容に準拠して、これらのメソッドをsafeなものとして扱っています。
- GET
- HEAD
- OPTIONS
- TRACE
SameSite属性のデフォルト値
Google Chrome 80が2020年2月4日にリリースされました。その結果、SameSite属性が未設定の場合、以下がデフォルト値となります。
- Chrome 79まで
- SameSite=Noneとして扱われる。
- StrictかLax以外の値を指定した場合もSameSite=Noneとして扱われる。
- Chrome 80以降
- SameSite=Laxとして扱われる。
- StrictかNone以外の値を指定した場合もSameSite=Laxとして扱われる。
- つまりChrome 80以降では、明示的にNoneを指定しないと、Noneとして扱われない。
サンプルコードでSameSite属性を理解する
Node.jsのhttps
モジュールを用いて、Cookieの送信に関する動作確認を行いました。動作確認では、「https://localhost:8080/」と「https://127.0.0.1:8081/」の2つのサイトを用意することで、cross-site
でのリクエストを実現しています。
あわせて読みたい
『Node.jsのhttpsモジュールの使い方』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。 続きを見る【Node.js】httpsモジュールでサーバーを作成する方法
「https://localhost:8080/」と「https://127.0.0.1:8081/」のコードを以下に示します。
const https = require('https')
const fs = require('fs')
const options = {
key: fs.readFileSync('./private-key.pem'),
cert: fs.readFileSync('./server-cert.pem'),
}
/*
「https://localhost:8080/」のコード
*/
https
.createServer(options, (request, response) => {
// cookieを設定する
response.setHeader('Set-Cookie', [
'SameSiteStrict=value; SameSite=Strict',
'SameSiteLax=value; SameSite=Lax',
'SameSiteNone=value; SameSite=None; Secure',
])
response.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8',
})
response.write('<a href="https://127.0.0.1:8081">別ドメインのサイト(https://127.0.0.1:8081)に移動する</a>')
response.end()
})
.listen(8080)
/*
「https://127.0.0.1:8081/」のコード
*/
https
.createServer(options, (request, response) => {
response.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8',
})
const html = `
<html>
<head></head>
<body>
<p>
<a href="https://localhost:8080/">aタグでのリクエスト</a>
</p>
<p>
<form action="https://localhost:8080/" method="GET">
<button type="submit">formタグ(GETメソッド)でのリクエスト</button>
</form>
</p>
<p>
<form action="https://localhost:8080/" method="POST">
<button type="submit">formタグ(POSTメソッド)でのリクエスト</button>
</form>
</p>
<p>サイトをまたぐリソースの読み込み(imgタグ)</p>
<img src="https://localhost:8080/">
</body>
</html>
`
response.write(html)
response.end()
})
.listen(8081)
上記のコードをNode.jsで実行して(node ファイル名
で実行できます)、HTTPSサーバを起動します。その後、Webブラウザで「https://localhost:8080/」にアクセスしてリクエストを行います。「https://localhost:8080/」にリクエストをした際のレスポンスヘッダを以下に示します(無関係なフィールドについては省略しています)。
HTTP/1.1 200 OK
Set-Cookie: SameSiteStrict=value; SameSite=Strict
Set-Cookie: SameSiteLax=value; SameSite=Lax
Set-Cookie: SameSiteNone=value; SameSite=None; Secure
「https://localhost:8080/」にアクセスし、デベロッパーツールで確認すると、以下に示すように、上記に示す3種類のCookieがWebブラウザに保存されていることがわかります。
「https://localhost:8080/」の画面に表示されているリンクで「https://127.0.0.1:8081/」に移動します。Cookieの送信検証は全て、「https://127.0.0.1:8081/」から「https://localhost:8080/」にリクエストを送ることで行います(ドメインが異なるためcross-site
なリクエストになります。つまり、SameSite属性がStrictのCookieは常に送信されません)。
aタグによるリクエストでのCookieの送信検証
a
タグによるリクエストを行った際のリクエストヘッダを以下に示します(無関係なフィールドについては省略しています)。
GET / HTTP/1.1
Cookie: SameSiteLax=value; SameSiteNone=value
Host: localhost:8080
Referer: https://127.0.0.1:8081/
GET
メソッドなので安全なメソッド(Safe Methods)です。また、「https://127.0.0.1:8081/」がリクエストしたURLは「https://localhost:8080/」であり、アドレスバーにも「https://localhost:8080/」が表示されているので、トップレベルナビゲーションです。
以上より、SameSite属性がNoneのCookieだけでなく、LaxのCookieも「https://localhost:8080/」に送信されています。
formタグによるリクエストでのCookieの送信検証
form
タグ(GET
メソッド)によるリクエストを発行した際のリクエストヘッダを以下に示します(無関係なフィールドについては省略しています)。
GET / HTTP/1.1
Cookie: SameSiteLax=value; SameSiteNone=value
Host: localhost:8080
Referer: https://127.0.0.1:8081/
a
タグによるリクエストと同じで安全なメソッド(Safe Methods)かつトップレベルナビゲーションなので、SameSite属性がNoneのCookieだけでなく、LaxのCookieも「https://localhost:8080/」に送信されています。
form
タグ(POST
メソッド)によるリクエストを発行した際のリクエストヘッダを以下に示します(無関係なフィールドについては省略しています)。
POST / HTTP/1.1
Cookie: SameSiteNone=value
Host: localhost:8080
Referer: https://127.0.0.1:8081/
トップレベルナビゲーションですが、POST
メソッドなので、SameSite属性がNoneのCookieのみが「https://localhost:8080/」に送信されています。
imgタグによるリクエストでのCookieの送信検証
img
タグによるリクエストを発行した際のリクエストヘッダを以下に示します(無関係なフィールドについては省略しています)。
GET / HTTP/1.1
Cookie: SameSiteNone=value
Host: localhost:8080
Referer: https://127.0.0.1:8081/
GET
メソッドなので安全なメソッド(Safe Methods)ですが、トップレベルナビゲーションではないので、SameSite属性がNoneのCookieのみが「https://localhost:8080/」に送信されています。
今回、a
タグ・form
タグ・img
タグでCookieの送信検証をしてきましたが、sameSite属性による動作の挙動をまとめると以下のようになります。今回動作確認していないものも含めています。
same-site | cross-site | |||||
strict | Lax | None | strict | Lax | None | |
aタグ | 〇 | 〇 | 〇 | × | 〇 | 〇 |
imgタグ | 〇 | 〇 | 〇 | × | × | 〇 |
ifameタグ | 〇 | 〇 | 〇 | × | × | 〇 |
formタグ (GETメソッド) | 〇 | 〇 | 〇 | × | 〇 | 〇 |
formタグ (POSTメソッド) | 〇 | 〇 | 〇 | × | × | 〇 |
XMLHttpRequest | 〇 | 〇 | 〇 | × | × | 〇 |
Fetch | 〇 | 〇 | 〇 | × | × | 〇 |
上記の表のポイント
same-site
なリクエスト- SameSite属性が何であろうとCookieが送信される。
cross-site
なリクエスト- SameSite属性がStrictの場合、どのリクエストでもCookieが送信されない。
- SameSite属性がNoneの場合、どのリクエストでもCookieが送信される。
- SameSite属性がLaxの場合、Cookieの送信条件が複雑で、安全なメソッド(Safe Methods)かつトップレベルナビゲーションの時のみCookieが送信される。
本記事のまとめ
この記事では『CookieのSameSite属性』について、以下の内容を説明しました。
- CookieのSameSite属性とは
- SameSite属性のStrictとLaxとNoneの違い
- SameSite属性のデフォルト値
- サンプルコードでSameSite属性の動作確認を行う
お読み頂きありがとうございました。