HTTPクッキーはあらゆる場所に存在しています。すべてのログインセッション、ショッピングカート、分析ツールはそれらに依存しています。しかし、多くの開発者はヘッダーをコピーして貼り付けて、属性が実際にどう機能するか、あるいは誤って設定された場合にどうなるかを理解せずに進んでいます。 Set-Cookie ヘッダーをコピーしてそのまま使うだけで、属性が実際にどう機能するか、あるいは誤って設定された場合にどうなるかを理解していない。
このガイドでは、クッキーの構造、すべての意味のある属性、クッキーストリングをパースする方法、そしてなぜ SameSite あなたのCSRF防御です。すぐに実践したい場合は、 IO Tools クッキーパーサー または クッキービルダー.
クッキーが実際にどのように見えるか
サーバーがクッキーを設定したい場合、次のヘッダーを送信します。 Set-Cookie レスポンスヘッダー:
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400
ブラウザはこれを保存し、次のリクエストで次のようになります。
Cookie: sessionId=abc123
これが全体の仕組みです。複雑さはその属性にあります。
クッキーの構造:文字列を分解する
クッキー文字列は一貫したフォーマットを持っています。
name=value; attribute1; attribute2=attributeValue; ...
の name=value ペアが最初に来ます。最初のセミコロン以降はブラウザへの指示であり、サーバーは受信するヘッダーにこれらの属性を確認しません。 Cookie ヘッダーを受信します。
安全な属性を正しく設定する
HttpOnly
HttpOnly JavaScriptがクッキーを読み取るのを防ぎます。 document.cookie. これはXSS攻撃がセッショントークンを盗むのを直接防ぐ直接的な防御です。
Set-Cookie: sessionId=abc123; HttpOnly
ユーザーを認証するすべてのクッキーには HttpOnlyが必須です。これは良い理由がないためです。
安全な
Secure ブラウザがHTTPS接続のみでクッキーを送信するようにします。そうでなければ、クッキーはHTTPで明文で送られ、盗まれる可能性があります。生産環境では、セッションクッキーは常に Secureが必要です。ローカル開発時に http://localhostでは、それを省略できます——ブラウザはlocalhostに対して例外を設けます。
SameSite
SameSite クロスサイトリクエストでブラウザがクッキーを含めるかどうかを制御します。これはCSRF攻撃に対する主な防御です。3つの値があります:
Strict— クッキーはクロスサイトリクエストで送信されません。最も安全ですが、ユーザーがメールからリンクをクリックするとログアウトされてしまいます(その初期ナビゲーションでクッキーが送信されません)。Lax— クッキーは外部サイトからのトップレベルナビゲーション(GETリクエスト)で送信されますが、埋め込みのクロスサイトリクエストやクロスサイトPOSTでは送信されません。これは、明示的なSameSite属性がないクッキーのブラウザデフォルトです。None— クッキーはすべてのクロスサイトリクエストで送信されます。第三者クッキー(OAuthフロー、埋め込みウィジェット)には必須です。これはSecure.
# Third-party / cross-site cookie (e.g., OAuth callback)
Set-Cookie: token=xyz; SameSite=None; Secure
と組み合わせて使用する必要があります。 SameSite=None without Secureを送信すると、現代のブラウザはクッキーを完全に拒否します。ほとんどのセッションクッキーでは SameSite=Lax — セキュリティと使いやすさのバランスを取るためです。
スコープ:ドメインとパス
Domain
の Domain 属性はどのホスト名にクッキーが送信されるかを指定します。
Set-Cookie: user=alice; Domain=example.com
の場合、クッキーは Domain=example.comおよびすべてのサブドメイン( example.com )に送信されます。api.example.com, app.example.com属性がない場合、クッキーはそのホスト名が設定された正確なオリジンにのみ送信されます——サブドメインには送信されません。 Domain 一般的な誤解:
はクッキーを Domain=example.com にのみ制限します。これはサブドメインを含む範囲を広げます。サブドメインアクセスが必要ない場合はこの属性を省略してください。 ない URLパスがクッキーを送信するトリガーを制限します。 example.comこのクッキーは
パス
Path およびその下のパスにのみ送信されます。
Set-Cookie: adminToken=xyz; Path=/admin
へのリクエストには含まれません。デフォルトは /admin で、すべてのパスを意味します。 / または /api Max-Age と Expires /どちらもクッキーが有効になるタイミングを制御します。Max-Ageを優先してください。
絶対的な日付(HTTP日付フォーマット)を指定します。これはクライアントの時計に基づいており、あなたが制御できません。
現在からの秒数を指定します: Max-Age.
Expires24時間分。サーバーの意図に基づく、クライアントの時計とは異なります。Max-Age両方がある場合、Max-Age=86400が優先されます。どちらの属性も指定されていないクッキーは
セッションクッキー Max-Age — ブラウザが閉じられるときに消えます。 クッキー属性の参照 属性
何をしますか
| JavaScriptがクッキーにアクセスをブロック | 設定されていない | デフォルト | おすすめ |
|---|---|---|---|
HttpOnly | 認証クッキーには常に設定 | HTTPSでのみ送信 | 生産環境では常に設定 |
Secure | クロスサイト送信を制御 | HTTPSでのみ送信 | 緩和(現代のブラウザ) |
SameSite | セッション用は緩和、第三者用はNone + Secure | ホスト名の範囲を設定 | 現在のホストのみ |
Domain | クロスサブドメインアクセスが必要ない場合に省略 | パスの範囲を設定 | /をそのまま残す、管理トークンを分離したい場合を除く |
Path | 有効期限までの秒数 | / | セッションクッキー |
Max-Age | Expiresよりも優先 | 絶対有効期限日付 | Max-Ageを使用 |
Expires | 設定する | 絶対有効期限日付 | Max-Ageを使用 |
コード内でクッキーを設定する
Node.js (Express)
app.post('/login', (req, res) => {
// ... verify credentials ...
res.cookie('sessionId', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 86400 * 1000, // milliseconds in Express
path: '/',
});
res.json({ ok: true });
});
Python (FastAPI)
from fastapi import FastAPI, Response
app = FastAPI()
@app.post("/login")
def login(response: Response):
# ... verify credentials ...
response.set_cookie(
key="sessionId",
value=token,
httponly=True,
secure=True,
samesite="lax",
max_age=86400,
path="/",
)
return {"ok": True}
手動でクッキーヘッダーをパースする
の Cookie サーバーが受信するヘッダーには name=value ペアのみが含まれており、 ; :
Cookie: sessionId=abc123; theme=dark; lang=en
で区切られています。 ; セミコロンとスペースで分割し、それぞれのペアを 最初の = だけに分割します。考慮すべきエッジケース:
- 値には
=(base64文字列がよく使われる) — 常に最初の=だけに分割します。 - クッキー名は大文字小文字を区別します
- セパレータの周囲の空白は変動する可能性がある——両側をトリムして防御的に処理します
自作で分割ロジックを書く代わりに、 IO Tools クッキーパーサー をデコードし、各値を確認するか、または Cookie IO Tools クッキービルダー を用いて、正しい属性を持つ有効な ヘッダーを構築できます。 Set-Cookie クッキーとCSRF
クロスサイトリクエストフォージェリーは、ブラウザが異なるサイトから開始されたリクエストにも自動的にクッキーを含めるという事実を悪用しています。悪意のあるページが
に存在し、そのページが evil.com にフォームを提出する場合、ユーザーがログインしているなら、ブラウザはそのセッションクッキーをフォージャーされたリクエストと共に送信します。 bank.com/transferは、典型的な攻撃パターンであるクロスサイトPOSTリクエストにクッキーを含めないため、ほとんどのCSRFベクトルを防いでいます。
SameSite=Lax はさらに徹底的ですが、使い勝手に影響を与える可能性があります。 SameSite=Strict CSRFトークンは、高リスク操作や
が第三者のコンテキストで必要である場合に、防御の深さとして残ります。この2つの防御は互いに補完されます。 SameSite=None 第三者のコンテキストには必要です。この2つの防御は互いに補完しています。
