CSRF(Cross-Site Request Forgery)—は、攻撃者が被害者のブラウザーに認証されたユーザーに代わってターゲットサーバーへ偽造されたリクエストを送らせるタイプの攻撃です。OWASP、2026によると、CSRFはウェブアプリケーションに対する最も重大なリスク10項の中の1つです。モバイル開発の文脈では、CSRF攻撃はクッキー認証を使用するREST APIに対して特に危険です。クロスサイトリクエストフォージェリは、現代的な保護メカニズムの導入にもかかわらず、依然として重要な脅威であり続けています。
まとめ
CSRF(Cross-Site Request Forgery)—は、攻撃者が偽造リクエストを作成し、被害者のブラウザーにそれをターゲットサーバーへ送らせる攻撃です。サーバーはユーザーの現在のセッションから有効なクッキークレデンシャルを受け取るため、リクエストを実行します。リクエストがどのページから送られたかに関係なく、ブラウザーが自動的にターゲットドメインへの各リクエストにクッキーを追加するため、攻撃が可能になります。ユーザーは攻撃者のページを見ることさえないかもしれません—悪意のあるURLを持つ隠しエレメント(<img>、<form>、<iframe>)を読み込むだけで十分です。CSRFは直接データを盗みません—攻撃は被害者に代わって行動(状態変更オペレーション)を実行します。例えば、資金の振り込み、パスワード変更、アカウント削除などです。
CSRF攻撃は状態を変更するオペレーションのみを対象とします—付作用のあるGETリクエスト、POST、PUT、DELETEです。例えば、個人アカウントのメールアドレス変更リクエスト:サーバーがリクエストのオリジンを確認せずに受け入れる場合、攻撃者は自分のメールを代わりに設定し、パスワードリセットを始めることができます。この攻撃は、一つの行動が重大な影響をもたらす銀行システム、管理者パネル、ソーシャルネットワークに対して特に危険です。クッキーを認証に使用するモバイルアプリAPIも、追加のチェックを行わない場合はCSRFの影響を受けやすくなります。
クッキーに基づく認証を使用し、サーバーがリクエストのオリジンを確認しないウェブアプリケーションやAPIはすべて脆弱です。Webフォームを通じた認証にWebViewを使用するモバイルアプリもリスクがあります:ブラウザコンポーネントが自動的にクッキーを送信し、攻撃者はバックグラウンド読み込みを通じて悪意のあるリクエストを挿入できます。HackerOne(2025)によると、ウェブアプリの脆弱性レポートの約12%がCSRF保護の缺如に関連しています。
CSRFの主な特徴は、被害者にとって見えないことです。ユーザーは攻撃が発生したことさえ気づかないかもしれません—偽造リクエストはバックグラウンドで実行され、アプリケーションインターフェースにハッキングの征候は表れません。CSRFを検知するだけの方法は、サーバーログを監視するか、アカウントの突然の変化に気づくことです。さらに、CSRFはXSSやオープンリダイレクトなど他の脆弱性と組み合わせやすく、被害が何倍にも拡大されます。
CSRF攻撃には3つの条件が必要です:被害者がターゲットサイトで認証されていること、サーバーがクッキー認証を使用していること、攻撃者のリクエストがアクションURLに向けられていることです。攻撃者は、src属性がターゲットURLを指すフォーム、スクリプト、または画像を含むHTMLページを作成します。被害者のブラウザーがこのページを読み込み、自動的に現在のセッションクッキーと共にサーバーへリクエストを送信します。サーバーは有効なクッキーを受け取り、リクエストのソースを確認せずにオペレーションを実行します。
<!-- 隠しフォームを使ったCSRF攻撃の例 -->
<form action="https://bank.example.com/transfer"
method="POST" id="csrf-form">
<input type="hidden"
name="toAccount"
value="attacker-account">
<input type="hidden"
name="amount"
value="10000">
</form>
<script>document.getElementById("csrf-form").submit()</script>
ページが読み込まれた後、スクリプトが即座にフォームを送信します。ブラウザーはbank.example.comへのPOSTリクエストにユーザーのセッションクッキーを添付します。銀行のサーバーはクッキーを確認し、ユーザーが認証されていることを確認し、攻撃者のアカウントへの振り込みを実行します。被害者は何もないまたは正規のページを見ていますが、お金はすでに移動しています。
HTTPプロトコルの主な特徴は、リクエストソースの組み込み確認機能がないことです。ブラウザーは、リクエストのドメインがクッキーのドメインと一致する場合、リクエストにクッキーを追加します。攻撃者はクッキーの内容を知る必要がありません—ブラウザーが自動的に行います。同一オリジンポリシーは、攻撃がサーバーを対象とし、応答の読み取りではないため、CSRFから保護しません。CORSなどのメカニズムも無効です:CSRFリクエストは、被害を与えるために応答を読む必要がありません。
CSRF攻撃は、悪意のあるリクエストの配信方法によって分類されます。各種類はリクエストを送るために異なるHTML要素を使用しますが、すべてがブラウザーによる自動的なクッキー送信に依存しています。方法の選択は攻撃者の目的によります:GETベースの攻撃は少ないコードで実行でき、POSTベースの攻撃はいくつかの保護をより組みやすく回避でき、XMLHttpRequestベースの攻撃はヘッダーを操作できます。
| 攻撃の種類 | 配信ベクトル | HTTPメソッド | 検知の難しさ |
|---|---|---|---|
| GETベース | <img>、<script>、<iframe> | GET | 高い |
| POSTベース | 隠し<form> + 自動送信 | POST | 中程度 |
| XHRベース | CORS付きXMLHttpRequest | 任意 | 低い |
最も簡単な方法:攻撃者がリクエストパラメータを含むURLを持つ<img>をページ上に配置します。ブラウザーが画像を読み込み、GETリクエストをサーバーに送信します。例えば、<img src="https://api.example.com/delete?postId=123" />は、サーバーがDELETEをGETで処理している場合、レコードを削除します。明らかな危険性にもかかわらず、一部のAPIでは依然として削除や更新にGETが使用されています。
サーバーがPOSTリクエストのみを受け付ける場合、攻撃者はPOSTメソッドの隠しフォームを作成し、JavaScriptを通じて自動的に送信します。フォームは画面に表示されず、autofocus + .submit()がユーザーのクリックなしで発火します。POSTベースの攻撃は、サーバーがContent-Typeヘッダーを確認する場合は動作しませんが、多くのAPIは標準的なapplication/x-www-form-urlencodedを受け付けます。
XMLHttpRequestやFetch APIは、任意のヘッダーを持つリクエストを送信できます。サーバーがCORSを広範に設定している場合(Access-Control-Allow-Origin: *)、攻撃者は任意のリクエストを送信し、応答を読むことができます。ただし、CSRF攻撃には応答を読む必要はありません—アクションを実行するだけで十分です。現代のブラウザーは非標準リクエストの前にpreflightリクエストOPTIONSを送信するため、サーバーが正しく構成されていればXHRベースのCSRFをブロックできます。
ネイティブアプリはめったにクッキー認証を使用しないため、モバイルアプリケーションはウェブサイトよりもCSRFに対する脆弱性が低いです。代わりに、モバイルAPIはAuthorizationヘッダー(Bearerトークン、JWT)にトークンを使用することが多いです。ただし、CSRF攻撃が可能なシナリオもあります:WebログインのあるWebView、ハイブリッドアプリ、クッキーベースのセッションを使用するAPIです。TechCrunch(2025)によると、約18%の公開モバイルアプリAPIがまだセッションクッキーをサポートしています。
多くのアプリはWebページをWebViewで開きます—OAuth認証、支払いフォーム、コンテンツの表示などです。WebViewはアプリ内の完全なブラウザーで、セッションクッキーを保持します。攻撃者がオープンリダイレクトやディープリンクを通じて自分のURLをWebViewに読み込む方法を見つけた場合、普通のブラウザーと同じようにCSRF攻撃を実行できます。保護策—重要な操作にはWebViewの代わりにChrome Custom TabsやSFSafariViewControllerを使用します。
JWTトークンは通常localStorageまたはアプリのメモリに保存され、自動的には送信されません—開発者が明示的に各リクエストにAuthorizationヘッダーを追加します。これにより、古典的なCSRF攻撃は不可能になります。ただし、アプリがJWTをCookieに保存する場合(れではありますが可能です)、リスクが帰ってきます。追加保護—azpやaudクレームを通じてJWTを特定のリクエストオリジンに結び付けることで、異なるドメインでのトークンの使用を防ぐことができます。
// ExpressでのサーバーサイドCSRFトークン検証の例
const csrfProtection = (req, res, next) => {
const token = req.headers['x-csrf-token'];
if (!token || token !== req.session.csrfToken) {
return res.status(403).json({ error: 'CSRF validation failed' });
}
next();
};
// ログイン時のCSRFトークン生成
app.post('/api/login', (req, res) => {
const csrfToken = crypto.randomBytes(32).toString('hex');
req.session.csrfToken = csrfToken;
res.json({ csrfToken: csrfToken });
});
現代的なCSRF保護は3つのレベルで構築されています:サーバーサイドのCSRFトークン、Cookieに対するSameSite属性、Originヘッダーの確認です。これらの方法を組み合わせることで、UXに大きな影響を与えずに99%のCSRF攻撃から保護することができます。アプローチの選択はアプリケーションアーキテクチャに依存します:ウェブサイトにはSameSite=Laxだけで足りるかもしれませんが、モバイルアプリAPIにはヘッダー内のトークンが必要です。
標準的な方法:サーバーが固有のトークンを生成し、ユーザーのセッションに結び付け、クライアントに伝えます。クライアントは状態を変更する各リクエストにトークンを含めます(隠しフォームフィールドまたはX-CSRF-Tokenヘッダーに)。サーバーは受け取ったトークンをセッションに保存されているものと比較します。トークンは暗号学的に強固で、ランダムで、最低32バイトの長さがあり、セッションまたはオペレーションごとに変更される必要があります。トークンの有効期間は数時間を超えてはなりません。
Cookieに対するSameSite属性は、クロスドメインリクエストでのCookieの送信を制限します。Lax値は、トップレベルのナビゲーションGETリクエストにのみCookieを許可します—大多数のウェブサイトにはこれで十分です。Strictは、ナビゲーションを含むすべてのクロスドメインリクエストに対してCookieをブロックします:別のサイトからアクセスした場合、ユーザーは再認証が必要になります。Chrome Platform Status(2026)によると、SameSite=Laxはすべての現代ブラウザーでデフォルトで有効になっており、CSRF攻撃の数を67%減少させました。
サーバーは、入力リクエストのOriginまたはRefererヘッダーを確認できます。リクエストが異なるドメインから届いた場合、ブロックされます。OriginはRefererよりも信頼性が高く、POSTリクエストで常に存在し、ブラウザーポリシーで無効にできません。実装方法:許容されたオリジンのホワイトリストを作成し、現在のヘッダー値と比較します。この方法は有効ですが、Originヘッダーがないか偽造される可能性があるモバイルアプリでは実装が難しくなります。
// Spring BootでのCSRFトークン検証の例
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(
@Autowired http: HttpSecurity
): SecurityFilterChain {
return http
.csrf { it.csrfTokenRepository(
CookieCsrfTokenRepository.withHttpOnlyFalse()
) }
.sessionManagement {
it.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
}
.build()
}
}
サーバー上でトークンを保存する必要がない方法:サーバーがランダムな値を持つCookieを設定し、クライアントがCookieから値を読み取って、ヘッダーまたはリクエストボディに戻して送信します。サーバーは両方の値を比較します。攻撃者がCookieを読めない場合(同一オリジンポリシー)、トークンを偽造できません。この方法はシンクロナイザーより簡単に実装できますが、Cookieを盗聴から守るためにHTTPSが必要です。
CSRFとXSSは、よく混同される異なるタイプの攻撃です。CSRFは、ユーザーのブラウザーへのサーバーの信頼を悪用します:リクエストが有効なクッキーと共に届くため、サーバーは攻撃者のコマンドを実行します。XSSは、サーバーのコンテンツへのブラウザーの信頼を悪用します:ブラウザーが攻撃者によってページに挿入されたスクリプトを実行します。CSRFにはターゲットサイトへのコードの挿入が必要ありません—別のドメインからリクエストを送るだけで十分です。XSSは反対に、ページのHTMLコードにJavaScriptを挿入する方法を見つける必要があります。ただし、XSSはCSRF保護を回避できます:挿入されたスクリプトがページからCSRFトークンを読み取り、リクエストと共に送信します。
| 特徴 | CSRF | XSS |
|---|---|---|
| 攻撃目標 | サーバー | クライアント(ブラウザー) |
| ベクトル | リクエストの偽造 | スクリプトの挿入 |
| 被害者のサイトにJavaScriptが必要? | いいえ | はい |
| データの盗み | なし(アクションのみ) | あり |
| 保護 | CSRFトークン、SameSite、Origin | アウトプットエスケープ、CSP |
CSRFとXSSの違いを理解することは、多層保護を構築する上で重要です。CSRFトークンはXSSから保護せず、CSP(Content Security Policy)はCSRFから保護しません。すべての方法を組み合わせることで、両方のタイプの攻撃からアプリケーションを守ることができます。WebViewを使用するモバイルアプリでは、リスクが倍増するため、開発者はAPIリクエストにCSRFトークンを、ウェブコンテンツにContent Security Policyをそれぞれ実装することが推奨されます。
よくある質問
CSRFはサーバーにユーザーに代わって動作させ、XSSは被害者のブラウザーに悪意のあるスクリプトを挿入します。CSRFにはターゲットサイトへのコード挿入が必要ありません—別のドメインからリクエストを送れば十分です。XSSはCSRFと異なり、データを盗み、ページのコンテンツを読むことができます。
クッキー認証を使用しているかどうか、また状態変更オペレーションに対してリクエストのオリジン確認があるかどうかを確認してください。CSRFトークン、Origin確認、SameSiteなしでAPIがPOST/PUT/DELETEを受け入れている場合、アプリは脆弱です。自動スキャンにはOWASP ZAPまたはBurp Suiteを使用してください。
いいえ、CORSはCSRFから保護しません。CORSはクロスドメイン応答を安全に読むためのメカニズムであり、CSRF攻撃は応答を読む必要がありません—リクエストを送るだけで十分です。<form>や<img>を通じたCSRFリクエストはCORS制限の対象ではありません。
APIがクッキー認証を使用している場合、CSRF保護は必須です。APIがAuthorizationヘッダーでBearerトークンを使用している場合、トークンがブラウザーによって自動的に送信されないため、CSRFリスクは最小限です。ただし、WebViewを使用するハイブリッドアプリの場合、保護はまだ推奨されます。
SameSiteは2020年以降、すべての現代ブラウザーでサポートされています。古いブラウザーに対しては、主な保護方法としてCSRFトークンを使用してください。CSRFトークン+SameSiteの組み合わせは、レガシーブラウザーでSameSiteが無効であっても最大限の保護を提供します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。