#はじめに
「ログインしたまま悪意のあるサイトを開いたら、勝手に送金されていた」——これがCSRF(クロスサイトリクエストフォージェリ)攻撃です。
Cookieは便利な仕組みですが、何も対策しないと、ユーザーが意図しないリクエストにもCookieが送信されてしまいます。SameSite属性は、この問題を解決するための仕組みです。
この記事を読むと、以下のことができるようになります:
- CSRF攻撃の仕組みを理解できる
- SameSite属性の3つの値(Strict、Lax、None)の違いがわかる
- どの場面でどの値を使うべきかを判断できる
#「サイト」と「オリジン」の違い
SameSite属性を理解するには、まず「サイト」の定義を知る必要があります。
#オリジン(Origin)
オリジンは「スキーム + ホスト + ポート」で構成されます。
https://www.example.com:443
^^^^^^ ^^^^^^^^^^^^^^^ ^^^
スキーム ホスト ポート
これらのすべてが一致して初めて「同一オリジン」です。
#サイト(Site)
サイトは「スキーム + 登録可能ドメイン(eTLD+1)」で構成されます。
https://www.example.com
^^^^^^ ^^^^^^^^^^^
スキーム 登録可能ドメイン
「登録可能ドメイン」とは、パブリックサフィックス(.com、.co.jpなど)に1つのラベルを加えたものです。
#比較
| URL A | URL B | 同一オリジン | 同一サイト |
|---|---|---|---|
https://www.example.com | https://api.example.com | ❌ | ✅ |
https://example.com | https://example.com:8080 | ❌ | ✅ |
https://example.com | http://example.com | ❌ | ❌ |
https://example.com | https://example.org | ❌ | ❌ |
SameSite属性は「サイト」を基準に判断します。 サブドメインが違っても同一サイトです。
#CSRF攻撃とは
CSRF(Cross-Site Request Forgery)は、ユーザーの意図しないリクエストを、ユーザーの認証情報を使って送信させる攻撃です。
#攻撃の流れ
1. ユーザーがbank.comにログイン(認証Cookieを取得)
2. ユーザーが悪意のあるサイト evil.com を訪問
3. evil.com のページに仕込まれた不正なフォーム:
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="100000">
</form>
<script>document.forms[0].submit();</script>
4. ブラウザが bank.com にPOSTリクエストを送信
→ このとき、bank.com のCookieが自動的に付与される!
5. サーバーはCookieを見て正規のリクエストと判断し、送金を実行
ユーザーはbank.comにログインしたまま evil.com を訪問しただけで、知らないうちに送金が行われてしまいます。
#SameSite属性とは
SameSite属性とは、クロスサイトリクエストにCookieを送信するかどうかを制御する属性です。
Set-Cookie: session_id=abc123; SameSite=Lax
3つの値があります:
| 値 | 動作 |
|---|---|
Strict | クロスサイトリクエストには一切送信しない |
Lax | 安全なナビゲーション(リンククリックなど)のみ送信 |
None | すべてのリクエストで送信(Secure必須) |
#Strict
最も厳格な設定です。クロスサイトからのリクエストには、Cookieを一切送信しません。
Set-Cookie: session_id=abc123; SameSite=Strict
#動作例
[evil.com] [bank.com]
| |
|--- <a href="bank.com">リンク --->|
| Cookie: 送信されない ❌ |
| |
|--- <form action="bank.com"> ---->|
| Cookie: 送信されない ❌ |
#メリット
CSRF攻撃を完全に防げます。
#デメリット
外部サイトからのリンクでも Cookie が送信されないため、ユーザー体験が悪化する可能性があります。
例: Slackに貼られた社内ツールへのリンクをクリック → ログイン状態が維持されず、再ログインが必要
#適した用途
- 銀行の送金確認
- パスワード変更
- 二要素認証の設定
など、セキュリティが最優先で、外部からのアクセスを想定しない操作。
#Lax
バランスの取れた設定です。安全な「トップレベルナビゲーション」のみCookieを送信します。
Set-Cookie: session_id=abc123; SameSite=Lax
#「トップレベルナビゲーション」とは
ブラウザのアドレスバーのURLが変わるような遷移を指します。
| 操作 | Cookieの送信 |
|---|---|
リンクのクリック(<a href>) | ✅ |
| GETフォームの送信 | ✅ |
| POSTフォームの送信 | ❌ |
<img>、<iframe>、fetch | ❌ |
| JavaScriptによるPOSTリクエスト | ❌ |
#動作例
[evil.com] [bank.com]
| |
|--- <a href="bank.com">リンク --->|
| Cookie: 送信される ✅ |
| |
|--- <form method="POST"> -------->|
| Cookie: 送信されない ❌ |
#メリット
- 外部リンクからのアクセスでもログイン状態を維持
- POST/非同期リクエストによるCSRFは防止
#デメリット
- GETリクエストで状態変更を行う設計だと脆弱
- 完全な防御ではない
#適した用途
一般的なセッションCookieに最適です。多くのWebアプリケーションではLaxで十分です。
#None
すべてのクロスサイトリクエストでCookieを送信します。
Set-Cookie: session_id=abc123; SameSite=None; Secure
重要: SameSite=Noneを使用する場合、Secure属性が必須です。HTTPSでのみ送信されるようになります。
#動作例
[partner.com] [api.example.com]
| |
|--- iframe内でapi呼び出し -------->|
| Cookie: 送信される ✅ |
| |
|--- fetch() API呼び出し ---------->|
| Cookie: 送信される ✅ |
#適した用途
- サードパーティウィジェット(埋め込みコメント、決済フォームなど)
- 複数ドメインにまたがるSSOシステム
- 広告・アナリティクス(ただしプライバシー規制に注意)
#注意
SameSite=NoneはCSRF対策を放棄することを意味します。他の対策(CSRFトークンなど)が必要です。
#デフォルト動作
SameSite属性を指定しない場合、ブラウザはどのように動作するでしょうか?
#現在のブラウザの動作
主要なブラウザは、SameSite属性が指定されていない場合、Laxとして扱います。
# 明示的な指定なし
Set-Cookie: session_id=abc123
# ↓ ブラウザは以下と同様に解釈
Set-Cookie: session_id=abc123; SameSite=Lax
これは2020年頃から主要ブラウザで導入された変更です。
#過去との違い
以前は、SameSite属性を指定しないとNoneとして扱われていました。現在のデフォルトLaxは、よりセキュアな方向への変更です。
#実践: SameSite属性の確認
#DevToolsで確認
- DevToolsを開く
- 「Application」→「Cookies」を選択
- 「SameSite」列を確認
表示される値:
StrictLaxNone- 空白(デフォルト、Laxとして扱われる)
#コンソールでの警告
不適切なSameSite設定は、コンソールに警告が表示されます。
A cookie associated with a cross-site resource at https://example.com/
was set without the `SameSite` attribute. It has been blocked...
#SameSite属性の選び方
Cookieの用途は?
│
├── サードパーティでの利用が必要
│ └── SameSite=None; Secure(+ CSRFトークン)
│
└── ファーストパーティのみ
│
├── 外部リンクからのアクセスを許容
│ └── SameSite=Lax(推奨)
│
└── セキュリティ最優先
└── SameSite=Strict
多くの場合、Laxが最適なバランスです。
#まとめ
- SameSite属性はCSRF対策の重要な仕組み
- 3つの値:
Strict: クロスサイトでは一切送信しないLax: 安全なナビゲーションのみ送信None: すべて送信(Secure必須)
- デフォルトはLax(現代のブラウザ)
- 多くの場合、
Laxが最適 Noneを使う場合はCSRFトークンなど追加の対策が必要
#次のステップ
SameSite属性を理解したところで、次はSecure・HttpOnly・Partitioned属性について学びましょう。これらの属性を組み合わせることで、Cookieのセキュリティをさらに強化できます。