Webアプリケーションを開発・運用するうえで、セキュリティ対策は欠かせない要素です。その中でも、非常に厄介な攻撃手法のひとつがCSRF(クロスサイトリクエストフォージェリ)です。
CSRFの対策が不十分だと、ログイン中のユーザーが知らないうちに、意図しない操作を実行させられてしまうという危険があります。たとえば、オンラインバンキングの送金処理や、SNSの投稿、ショッピングサイトの購入操作などが、ユーザー本人の知らないうちに実行されてしまいます。
この記事では『CSRF』について、以下の内容を図を用いてわかりやすく解説します。
- CSRFとは?
- CSRFの仕組み
- CSRFの対策
- CSRFとSSRFの違い
CSRFとは?
CSRFは「Cross-Site Request Forgery(クロスサイトリクエストフォージェリ)」の略です。「シーサーフ」と略して呼ばれることもあります。
名前が難しく感じるかもしれませんが、それぞれの単語の意味を知るとイメージしやすくなります。
- Cross-Site(クロスサイト):他のWebサイトを経由して
- Request(リクエスト):Webへのリクエスト
- Forgery(フォージェリ):なりすまし
つまり、CSRFとは「ログイン中の正規ユーザーになりすまし、他のWebサイトを経由して、不正なリクエストを送信させる攻撃」です。この攻撃は、正規のユーザーがログインしている状態を悪用して、第三者(攻撃者)がそのユーザーになりすまして操作します。
たとえば、あなたが銀行のWebサイトにログインしている状態で、うっかり別の悪意あるWebサイト(攻撃者のページ)を開いてしまったとします。するとその悪意あるWebサイトが、あなたの知らないうちに「銀行の送金処理を勝手に実行するリクエスト」を送るよう仕掛けてくるのです。しかも、あなたのブラウザにはログイン中の証拠であるセッション情報(Cookie)が残っているので、銀行のサーバーは「正規のユーザーからのリクエストだ」と勘違いして、そのまま処理してしまいます。これが、CSRF(クロスサイトリクエストフォージェリ)という攻撃です。
この攻撃が成立するには、利用者がログイン状態であることと、WebサイトにCSRFに関するセキュリティ対策が施されていないことが条件です。
補足
CSRFは「XSRF」や「リクエスト強要」、「Session Riding(セッションライディング)」とも呼ばれることがあります。
CSRFの仕組み

上の図は、CSRF攻撃がどのように行われるかを示したものです。ここからは、その流れをステップごとに詳しく説明していきます。
ステップ1:ユーザーがログインする
あなた(ユーザー)は、銀行のWebサイト(https://example-bank.com
)にログインしているとします。
ログイン後は、ブラウザにはCookie(クッキー)にログイン情報が保存されています。具体的には、Webサイト側でログイン時に「セッションID(Session ID)」と呼ばれる一意の識別子をユーザーに発行します(セッションIDはログイン状態を識別するために必要です)。このセッションIDは、あなたのブラウザのCookieに保存され、以降のすべてのリクエストに自動的に添付されてサーバーに送られます。
たとえば、以下のようなリクエストをサーバーが受け取ると、「SESSION_ID=abcd1234
は、さっきログインした人のものだな」と判断して、マイページを表示してくれます。
GET /mypage HTTP/1.1
Host: example-bank.com
Cookie: SESSION_ID=abcd1234
つまり、セッションIDのおかげで、ユーザーは毎回ログインし直さなくても、しばらくの間そのまま操作を続けることができるのです。
ステップ2:攻撃者の用意した悪意のあるWebサイトを開いてしまう
攻撃者は「自動で送金する仕掛け」を埋め込んだ悪意のあるWebサイト(https://attacker.example.com
)を事前に作成しておきます。攻撃者は、このWebサイトのURLをSNSやメールであなたに送りつけます。
そのWebサイトには、次のような送金フォームが仕込まれており、正規のWebサイトの利用者がクリックするように誘導します。
<form action="https://example-bank.com/send-money" method="POST">
<input type="hidden" name="receiver" value="attacker_account">
<input type="hidden" name="amount" value="10000">
<button type="submit">クリックすると幸せになります</button>
</form>
見た目は「クリックすると幸せになれるボタン」と魅力的に見せかけています。しかし、クリックすると「銀行の送金機能」に対して、攻撃者の口座へ1万円を送金するリクエストを発生させる仕組みになっています。
補足
さらに悪質な場合、ユーザーがボタンを押す前に自動でフォームを送信するように設定されていることもあります。以下の<script>
タグがそれで、ページが読み込まれた瞬間にリクエストが勝手に送信されるのです。つまり、ユーザーの操作を一切必要とせず、裏で勝手に送金されてしまうということです。
<form action="https://example-bank.com/send-money" method="POST">
<input type="hidden" name="receiver" value="attacker_account">
<input type="hidden" name="amount" value="10000">
<button type="submit">クリックすると幸せになります</button>
</form>
<script>
document.forms[0].submit(); // 自動でフォームを送信
</script>
このように、攻撃者のWebサイトを1回開いただけで、ユーザーの意思とは関係なく不正なリクエストが送信されてしまうというのが、CSRFの恐ろしいポイントです。
ステップ3:そのボタンをクリックして不正なリクエストを送ってしまう
正規のWebサイトの利用者が、正規のWebサイトのCookie(セッションIDなど)を持った状態(つまりログイン済みの状態)で「クリックすると幸せになれるボタン」をクリックすると、次のような銀行サイトへのリクエストが送信されます。このとき、送信されるリクエストは次のような内容です。
POST /send-money HTTP/1.1
Host: example-bank.com
Cookie: SESSION_ID=abcd1234
receiver=attacker_account&amount=10000
リクエストは正規のWebサイトのユーザーが所持しているexample-bank.com
上のCookieを含んで送信されます。つまり、あなたが意図していなくても、「攻撃者への送金」というリクエストが、ログイン中のあなたの名義で送られてしまうのです。
ステップ4:ログイン中なので、本物のユーザーとして処理される
重要なのは、リクエストに含まれている 「SESSION_ID=abcd1234」 という部分です。このセッションIDは、あなたが銀行にログインしたときに発行されたもので、あなたのログイン状態を示す“証拠”のようなものです。そのため、このセッションIDがリクエストに含まれていることで、攻撃者が用意した「送金リクエスト」が、本物のユーザーの操作だと勘違いされて処理されてしまいます。結果として、あなたの銀行口座から、攻撃者の口座に送金されてしまう…ということが起こるのです。
このように、「ログイン中の正規ユーザーになりすまし、攻撃者が用意した別のWebサイト(ここでは、https://attacker.example.com)を経由して、正規ユーザーの知らないうちに勝手にリクエストを送らせる攻撃」がCSRFです。
CSRFの対策
CSRF攻撃は、「Webサーバーがリクエストの出どころを見分けられない」という性質を悪用した攻撃です。
たとえば、攻撃者が作った悪意のあるWebサイト(https://attacker.example.com
)から送られたリクエストなのか、正規サイト(https://example-bank.com
)から送られたリクエストなのかを区別できなければ、不正リクエストが通ってしまいます。
つまり、「このリクエストは本当に正規のユーザーが送ったのか?」を確認する仕組みがあれば、CSRFは防げるのです。
ここでは、代表的なCSRF対策を3つ紹介します。
対策①:CSRFトークンを使う(最も基本的な対策)
CSRF(クロスサイトリクエストフォージェリ)を防ぐための、もっともよく使われる方法が「CSRFトークン」を使うことです。
ユーザーがフォームなどからリクエストを送るときに、「攻撃者が推測できないランダムな値(=CSRFトークン)」を一緒に送ることで、サーバー側で「本当に正しいリクエストか?」を確認することができます。
たとえば、フォームに次のような「隠しフィールド」を追加します。
<input type="hidden" name="csrf_token" value="ランダムな値">
このCSRFトークンは、Webサーバーが生成して、ユーザーごとのセッション(ログイン情報)と一緒に保存しておきます。また、Webサーバーで生成したCSRFトークンをWebサイト利用者にあらかじめ渡しておき、リクエストを送信するときに、そのCSRFトークンの値も一緒にWebサーバーに送ります。
Webサーバーはリクエストを受け取ったら以下をチェックします。
- 送られてきたCSRFトークンの値
- Webサーバーで生成したCSRFトークンの値
この2つが一致すれば「本人が送った正しいリクエスト」だと判断できます。一致しなければ、不正なリクエストとして拒否します。
このCSRFトークンは、Webサイトの利用者とWebサーバーしか知らない値です。攻撃者が自分のページに偽のリクエストを作っても、このトークンを正しく入れることができないため、CSRF攻撃を防ぐことができます。
対策②:SameSite属性でCookieを制御する(Cookie対策)
CSRF攻撃は、「ユーザーのブラウザに保存されたログイン情報(Cookie)」を悪用して、本物のユーザーになりすますことで成立します。そのため、Cookieが勝手に送られないようにすることで、CSRF攻撃を防ぐことができます。
SameSite属性は、Cookieを「どんな時に送るか」制限する仕組みです。SameSite属性をLax
またはStrict
に設定することで、CSRF攻撃を緩和することができます。例えば、Set-Cookie
ヘッダーに以下のように設定することで、すべての他サイトからのリクエストに対してCookieを送らないように設定できます。
Set-Cookie: session_id=abc123; SameSite=Strict; Secure
属性 | 意味 |
---|---|
Strict | すべての他サイトからのリクエストに対してCookieを送らない。 |
Lax | GETメソッドのリンク遷移は許可、それ以外は拒否。 |
None | すべて許可。 |
CSRF攻撃は、ユーザーのブラウザに保存されたログイン情報(Cookie)を使います。攻撃者が作った悪意のあるWebサイト(https://attacker.example.com
)から、正規のサイト(https://example-bank.com
)にリクエストを送っても、SameSite=Strict
で「他サイトからのリクエストにはCookieを付けない」ようにしておけば、ログイン情報(セッションIDなど)がWebサーバーに送られなくなります。その結果、サーバー側は「このリクエストは未ログインの状態だな」と判断し、送金処理などを拒否することができます。
あわせて読みたい
『SameSite属性』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。 続きを見るCookieのSameSite属性とは?図やサンプルコードなどで分かりやすく解説!
対策③:Referer / Originヘッダーを確認する(リクエスト元チェック)
ブラウザがリクエストを送るとき、自動的に「どこから送られてきたリクエストなのか」を示すヘッダーを付けることがあります。たとえば、攻撃者が作った悪意のあるWebサイト(https://attacker.example.com
)から正規のサイト(https://example-bank.com
)にリクエストを送ると、次のようなヘッダーが付きます。
Origin: https://attacker.example.com
または
Referer: https://attacker.example.com
サーバーは、受け取ったリクエストのOrigin
やReferer
ヘッダーを確認し、「信頼できるオリジン(ドメイン)」からのリクエストだけを受け付けるようにすることで、CSRF攻撃を防ぐことができます。
たとえば、サーバーが次のように判断します。
Origin
がhttps://example-bank.com
→ OK(自分のサイトだから信頼できる)Origin
がhttps://attacker.example.com
→ NG(知らないサイトだから拒否!)
あわせて読みたい
『Referer / Originヘッダー』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。 続きを見るHTTPヘッダーの一覧!どんな種類があるの?
SSRFとCSRFの違い
CSRF(クロスサイトリクエストフォージェリ)とSSRF(サーバーサイドリクエストフォージェリ)は、どちらも「リクエストを偽造する攻撃」ですが、攻撃の対象や仕組みが大きく異なります。以下に両者の違いをまとめます。
項目 | CSRF | SSRF |
---|---|---|
略称 | Cross-Site Request Forgery | Server-Side Request Forgery |
読み方 | クロスサイトリクエストフォージェリ | サーバーサイドリクエストフォージェリ |
攻撃の目的 | ユーザーになりすまして意図しない操作を実行させる | 内部サーバーあるリソースに不正アクセス |
攻撃の対象 | ログイン中のユーザー | 内部サーバー |
前提条件 | ユーザーがログイン中でCookieなどの認証情報を持っている | 公開サーバーが外部から指定されたURLにアクセスする機能を持つ |
攻撃の手口 | 悪意あるWebサイトを通じてユーザーのブラウザから不正なリクエストを送信 | 公開ユーザーに細工されたURLを入力させ、公開サーバー側が内部サーバーにアクセス |
代表的な例 | 銀行の送金フォームがユーザーの知らないうちに送信される | 公開サーバーがhttp://192.168.0.10:8000/admin にアクセスしてしまう |
被害例 | 本人の知らないうちに送金、投稿、購入処理が実行される | 内部APIやメタデータサービスに不正アクセスされる |
あわせて読みたい
『SSRF(サーバーサイドリクエストフォージェリ)』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。 続きを見るSSRFとは?仕組み・攻撃例・対策をわかりやすく解説!
本記事のまとめ
この記事では『CSRF』について、以下の内容を説明しました。
- CSRFとは?
- CSRFの仕組み
- CSRFの対策
- CSRFとSSRFの違い
CSRFは、「ユーザーがログインしている」というごく日常的な状態を突き、気付かぬうちに不正操作を実行させる非常に厄介な攻撃です。しかし裏を返せば、CSRFトークンの実装・CookieのSameSite制御・Referer/Origin
ヘッダーのチェックといった基本対策をきちんと施すだけで、攻撃の大半は防げます。
お読み頂きありがとうございました。