Idea
Security
クロスサイト・リクエストフォージェリ(CSRF)について勉強してみた
2025年10月19日
2025年10月19日

こんにちは、けいこんぐらです!
今回は、クロスサイト・リクエストフォージェリ(CSRF: Cross-Site Request Forgery)について勉強したことをまとめてみます。
CSRF ってよく聞くけど、「どんな攻撃だったっけ?」って思うことが多いので、基本的なところから対策までを整理してみます ✍️
CSRF とは?
ログインしたユーザーからのリクエストについて、そのユーザーが意図したリクエストであるかどうかを識別する仕組みを持たないウェブサイトは、外部サイトを経由した悪意のあるリクエストを受け入れてしまう場合があります。
このようなウェブサイトにログインしたユーザーは、悪意のある人が用意した罠により、ユーザーが予期しない処理を実行させられてしまう可能性があります。
つまり、信頼されたユーザーになりすまして、ウェブサイトに対して不正なコマンドを送信する攻撃手法のことを指します 😎
CSRF による影響としてこんなものがあります。
- ユーザーが意図していない物品の購入
- ユーザーが意図していない退会処理
- ユーザーアカウントによる、SNS や問い合わせへの書き込み
- ユーザーのパスワードやメールアドレスの変更
CSRF の仕組み
例えば、以下のようなパスワード変更処理があるとします。
<?php
function ex($s)
{
echo htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
}
session_start();
$id = @$_SESSION['id'];
/* ログイン状態の確認... */
$pwd = filter_input(INPUT_POST, 'pwd');
/* パスワードの変更処理... */
?>
パスワード変更に必要な条件は以下の通りです。
- POST メソッドで
change_password.php
にアクセスする - ログイン状態である
pwd
パラメータに新しいパスワードを指定する
ユーザーがウェブサイトにログインしている状態で、以下のような HTML が仕込まれたウェブページを閲覧すると、ユーザーのパスワードが意図せず変更されてしまいます 💦
<body onload="document.form[0].submit()">
<form action="http://xxx.com/change_password.php" method="POST">
<input type="hidden" name="pwd" value="hacked_password" />
</form>
</body>
流れとしては以下の図のようになります。
② の時点で、ログイン情報は自動的に罠サイトに送信されてしまうため、③ の POST リクエストでパスワードが変更されてしまいます。
Warning
CSRF 自体は、攻撃者が画面を参照できないため、情報を直接盗み出すことはできませんが、パスワード変更などの操作を行わせることで、不正ログインを可能にし、結果的に情報を盗み出すことが可能になります。
脆弱性のあるサイトの特徴
CSRF 攻撃の対象となるサイトとして、以下のようなものがあります。
- Cookie を用いたセッション管理
- HTTP 認証、TSL クライアント認証を用いたユーザーの識別
上記の特徴を持つサイトでは、リクエストに対してユーザーが意図したものであるかどうかを識別する仕組みがない場合、CSRF 攻撃の対象となる可能性があり、該当するサイトを運営している場合は、CSRF 対策を検討する必要があります 👀
脆弱性の原因
以下の Web の仕様が、CSRF 脆弱性の原因となっています。
1. form 要素の action 属性などに外部サイトの URL が指定できる
罠サイトなどの別サイトからでも、攻撃対象サイトの URL を指定してリクエストを送信できる
2. Cookie に保管されたセッション ID は、対象サイトにアクセスする際に自動的に送信される
罠サイト経由で攻撃対象サイトにアクセスしても、Cookie に保管されたセッション ID が自動的に送信される 🔐
つまり、攻撃対象となるサイトにログインしているユーザーが罠サイトを閲覧した場合、そのユーザーになりすましてリクエストを送信できてしまう。
例えばこんな感じで、異なるサイトからのリクエストでも Referer が異なるだけで、Cookie は自動的に送信されてしまいます、、
POST change_password.php HTTP/1.1
Referer: http://example.com/index.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
Cookie: PHPSESSID=xxxxxxxxxxxxxx
Host: xxx.com
pwd=password
POST change_password.php HTTP/1.1
Referer: http://trap.com/index.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
Cookie: PHPSESSID=xxxxxxxxxxxxxx
Host: xxx.com
pwd=password
Note
Cookie の SameSite 属性を設定することで、CSRF 攻撃を防止できる場合がありますが、全てのブラウザで対応しているわけではないなどの問題もあるため、他の対策も併用することが良いと思います!
対策
対策としては、ユーザーの意図したリクエストを確認することが重要になります 👍
1. CSRF 攻撃が可能なページにトークン情報を埋め込む
まず、ユーザーの入力内容を確認画面として出力する際、合わせてトークン情報を「hidden パラメータ」に出力するようにします。
このトークン情報は第三者が知り得ない秘密情報である必要があるため、生成するトークン情報は暗号論的擬似乱数生成器を用います。
次に確認画面から登録処理のリクエストを受けた際は、リクエスト内容に含まれる「hidden パラメータ」の値と、トークン情報とを比較し、一致しない場合は登録処理を行わないようにします 🙅♂️
Warning
このリクエストは、POST メソッドを使用します。
GET メソッドで行った場合、 Referer によりトークン情報が漏洩する可能性があるためです。
2. パスワードの再入力を求める
これはシンプルですが、ユーザーにパスワードの再入力を求めることで、CSRF 攻撃を防止する方法です。
この実装を行う場合は、必ず最終確認画面でパスワードの再入力を求めるようにします ⌨️
Warning
ユーザーの利便性が低下するとともに、画面設計の仕様変更にもなりかねないため、なりすましへの対策や確認を強く求める場面で適用することが望ましいと思います。
3. Referer の確認
「脆弱性の原因」のところで説明した通り、CSRF 攻撃では Referer ヘッダーが攻撃元サイトの URL になるため、リクエストの Referer を確認し、自サイトの URL と異なる場合は処理を中断する方法です 🙅♂️
Caution
ブラウザやパーソナルファイアウォール等の設定で Referer を送信しないようにしている場合、リクエストが実行できなくなってしまうため、注意が必要です。
4. 保険的な対策
上記の対策を行った上で、以下のような保険的対策を行うことも有効です。
- ユーザーの権限が必要で重要な操作を行った場合、メール等で通知する
CSRF への直接的な対策ではありませんが、ユーザーが不正な操作に気づきやすくなるため、有効な手段といえます 🙆♂️
まとめ
今回は、CSRF について勉強したことをまとめてみました!
CSRF の脆弱性に関する届出は、全体的にみて多くはないみたいですが、継続的に発生していて、発生すれば大きな被害につながる可能性があるため、ウェブアプリケーションを開発・運用する際は、CSRF 脆弱性に対する理解と対策が重要になると思います!
以上の内容が、CSRF について理解を深める一助となれば幸いです ✨
前の記事
ts-pattern を使って TypeScript にパターンマッチングを導入するメリットと実践的な使い方をわかりやすく解説します。