CSRF(クロスサイトリクエストフォージェリ)は、ログイン済みの利用者を利用して、本人が意図しない操作をサーバに送らせる攻撃です。 SameSite Cookieの普及で成立条件は狭まりましたが、消えてはおらず、トークンとの組み合わせで守るのが確実です。
CSRFとは
CSRF(Cross-Site Request Forgery、クロスサイトリクエストフォージェリ):ログイン中の利用者のブラウザに、攻撃者が用意したリクエストを自動送信させ、本人の権限で意図しない操作を実行させる攻撃です。 ブラウザがリクエストにCookieを自動で付ける仕組みを悪用します。
利用者が攻撃者のページを開くだけで、裏側で正規サイトへの送信が行われます。 パスワードやメールアドレスの変更、送金、退会など、本人にしかできない操作を勝手に実行されます。 かつて主要な脆弱性でしたが、ブラウザのSameSite Cookie既定化で緩和され、いまは限定的な条件で残る問題になっています。
CSRFが起きるパターン
典型的な弱点は次のとおりです。
- 状態を変える操作(送金、変更、削除)を、Cookieの認証だけで受け付けている
- CSRFトークンを検証しておらず、正しいCookieさえあればリクエストを通してしまう
- SameSite属性がNoneのCookieで、クロスサイトからの送信でも認証が通る
- 重要操作でパスワードの再入力などの追加確認を求めていない
- GETリクエストで状態を変える設計になっており、画像やリンクの読み込みだけで発火する
- APIがCookie認証を受け付け、かつCORSやSameSiteの設定が緩く、クロスサイトからの送信を許している
共通するのは「Cookieが自動送信されるだけで操作が成立し、正規の画面からの送信かを確認していない」という点です。
対策法
原則は「Cookieの自動送信だけでは操作を通さず、正規サイト由来のリクエストであることを確かめる」ことです。
- CSRFトークンを発行し、リクエストに含まれる値をサーバ側で検証する。これが本命の対策になる
- Cookieに
SameSite属性(LaxまたはStrict)を付け、クロスサイトからの送信を抑える - 送金や退会など重要操作では、パスワードの再入力や再認証を求める
- 状態を変える操作はGETで受け付けず、副作用のある操作をPOSTなどに限定する
SameSiteは広く効く土台ですが、それだけに依存せずトークン検証を併用するのが確実です。 フレームワーク標準のCSRF対策を有効にできているかを確認し、そのうえでSameSiteを重ねるのが費用対効果の高い順序になります。
Rails での事例
Rails は CSRF トークンの発行と検証を標準で行います。 フォームヘルパーが hidden フィールドにトークンを埋め、コントローラ側が照合します。 事故が起きるのは、この検証を自分で外したときです。
# 危険:SPA からの POST が 422 で弾かれたのを「解決」するために検証を外す
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
end
Cookie でセッション認証しているかぎり、検証を外したエンドポイントはそのまま CSRF の穴になります。
skip_before_action :verify_authenticity_token は Webhook 受信のような Cookie 認証を使わない経路に限定し、使用箇所をレビューで管理します。
SameSite は Rails 6.1 以降、セッション Cookie に Lax が既定で付きます。
明示するなら次のとおりです。
# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store,
key: "_app_session", same_site: :lax, secure: Rails.env.production?
React(TypeScript)での事例
Rails と React を組み合わせ、Cookie のセッション認証を使う構成では、フロント側がトークンをリクエストに載せる必要があります。
レイアウトの csrf_meta_tags が出力する meta タグから読み取り、ヘッダで送ります。
function csrfToken(): string {
return document.querySelector<HTMLMetaElement>('meta[name="csrf-token"]')?.content ?? "";
}
await fetch("/api/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": csrfToken(),
},
credentials: "same-origin",
body: JSON.stringify(payload),
});
fetch が 422 で弾かれたとき、最悪の直し方はサーバ側の検証を外すことです。 正しい直し方は、このヘッダをフロントの API クライアントに一箇所で組み込むことです。
なお、Cookie を使わず Authorization ヘッダでトークンを送る認証方式なら、ブラウザが認証情報を自動送信しないため、CSRF はそもそも成立しません。
その場合の主戦場は、トークンの保管場所の問題(XSS による窃取)に移ります。
まとめ
CSRF対策の要点を整理します。
- 成立条件は「Cookieが自動送信されるだけで操作が成立し、正規の画面からの送信かを確認していないこと」。ブラウザの仕組みの悪用なので、アプリ側で確かめる仕掛けが要る
- 本命の対策はCSRFトークンのサーバ側検証。SameSite Cookie(LaxまたはStrict)は広く効く土台だが、それだけに依存しない
- フレームワーク標準のCSRF対策を有効に保つ。
skip_before_action :verify_authenticity_tokenのような検証の無効化は、Cookie認証を使わない経路に限定してレビューで管理する - 状態を変える操作をGETで受け付けず、送金や退会などの重要操作では再認証を重ねる
Authorizationヘッダ方式の認証ならCSRFは成立しないが、代わりにトークンの保管場所(XSS耐性)が主戦場になる
「422で弾かれたから検証を外した」という箇所が最大の穴になりやすいので、既存コードの点検は検証を無効化している箇所の洗い出しから始めるのが近道です。
関連して読める記事
XSSとSQLインジェクションも、CSRFと並んでWebアプリケーションの定番の脆弱性です。とくにXSSは、CSRFトークンで守っていてもトークンごと盗まれる関係にあるため、セットで点検すると防御の穴を塞ぎやすくなります。また、「認証は通っているのに不正な操作が成立する」という構図はIDORとも共通します。

XSS(クロスサイトスクリプティング)とは?起きるパターンと対策法
XSS(クロスサイトスクリプティング)の仕組みと3つの型、混入しやすいパターン、そして出力時のエスケープを軸にした対策を整理します。React(TypeScript)の dangerouslySetInnerHTML と Rails(ERB)の raw / html_safe を題材に、危険なコードと安全な書き方を具体的なコード例で示します。
2026年7月22日
SQLインジェクションとは?起きるパターンと対策法
SQLインジェクションの仕組みと起きるパターン、そしてプレースホルダ(パラメータ化クエリ)を軸にした対策を整理します。Rails(Active Record)で穴が開く where の文字列展開と order のカラム名、その安全な書き方を具体的なコード例で示します。
2026年7月22日
IDOR(安全でない直接オブジェクト参照)とは?起きるパターンと対策法
IDOR(安全でない直接オブジェクト参照)の仕組みと起きるパターン、所有者チェックを軸にした対策を整理します。RailsのOrder.find(params[:id])がそのまま穴になる理由と、current_user起点の取得への直し方を具体的なコード例で示します。OWASP API Security Top 10で1位のBOLAに相当する脆弱性です。
2026年7月23日