テック技報最新号へ →
セキュリティ

CSRF を 3 つの関門で考える(CORS / SameSite / Origin・Sec-Fetch-Site 検証)

クッキー付き CSRF が刺さるのは「ブラウザが送る」「クッキーが付く」「サーバーが受け取る」の 3 つを全部突破されたとき。どこで止めるかを意識して設計し、サーバー側では Origin / Sec-Fetch-Site 検証を入れる。

@calloc134 · 2026-10-09
#csrf#web#appsec#cookies

3 つの関門(@calloc134 の整理)

  1. ブラウザが送信を許容するか: CORS の有無。CORS があっても GET や simple request(application/x-www-form-urlencoded 等)判定でプリフライトなしに送れてしまうか。
  2. クッキーが付属するか: SameSite 属性(Lax / Strict)。
  3. サーバーが受け取るか: Origin ヘッダや Sec-Fetch-Site の検証があるか。

実装例(サーバー側の検証)

ts
// 状態変更リクエストで Origin / Sec-Fetch-Site を検証する middleware の例
const ALLOWED = new Set(['https://app.example.com']);
function csrfGuard(req, res, next) {
  if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) return next();
  const site = req.headers['sec-fetch-site'];
  if (site && site !== 'same-origin' && site !== 'none') return res.status(403).end();
  const origin = req.headers['origin'];
  if (origin && !ALLOWED.has(origin)) return res.status(403).end();
  if (!site && !origin) return res.status(403).end(); // 両方欠けたら拒否(要件次第)
  next();
}
  • セッションクッキーは SameSite=Lax 以上 + Secure + HttpOnly。
  • GET で状態変更しない。

議論のポイント

  • 決定打は Origin ヘッダ検証という意見(@calloc134)がある一方、OWASP は CSRF トークンを主要対策として推奨。古いブラウザや Origin が付かないケースを考慮するならトークン併用が無難。
  • Next.js の Server Actions は Origin と Host の比較で CSRF を防ぐ設計だが、その前提を疑う声もある(@ysknsid25)。リバースプロキシ構成では Host / X-Forwarded-Host の扱いを確認。

出典

X の元の投稿を開く