【レースコンディション編】タイミングの隙間を突く攻撃と守り方|CTF思考フレームワーク #12
📖 この記事はシリーズの一部です
「CTF思考フレームワーク」 Web脆弱性編 #12 / 公開中 10記事 → シリーズ一覧を見る →
レースコンディションは、説明されると「なるほど」と思えるのに、実装時には見落とされやすい脆弱性です。残高確認、クーポン適用、在庫減算、ポイント付与、抽選応募など、「確認してから更新する」処理に、同時実行のズレが入り込むと不整合が起きます。
たとえば、同じ残高を複数の処理が同時に読み込んだり、1回限りのクーポン適用が並列処理で複数回通ったり、在庫数の更新が競合したりするケースです。見た目は地味ですが、決済・ポイント・在庫・紹介制度など金銭や権利に関わる部分では、実害が大きくなりやすいテーマです。
注意:この記事で扱う考え方は、必ずCTF・自分の検証環境・許可された診断範囲でのみ使ってください。実在するECサイト、金融サービス、ポイントサービス、サブスクサービスなどで試すことは、不正利用や規約違反、犯罪につながる恐れがあります。

レースコンディションは、同時実行された処理に対して状態管理が追いつかないことで、残高・ポイント・クーポンなどに不整合が起きる脆弱性だよ💸
難易度:★★★(中級〜上級) / 所要:10〜12分 / 前提:CTF思考フレームワーク #11
👀 観察フェーズ:まず何を見る?

まず「読み込み → 判定 → 更新」が分かれている処理を探す!在庫減算、ポイント消費、クーポン適用、出金処理などは要注意だよ🔍
レースコンディションは、「チェック」と「実行」の間にスキマがあるほど起きやすくなります。1回の処理に見えても、内部では複数のDBクエリ、外部サービス呼び出し、キャッシュ更新、メッセージキュー処理などに分かれていることがあります。

同じ状態を複数の処理が同時に読んでしまうと、どちらも「まだ使える」と判断してしまうことがあるんだね…😨
🤔 仮説フェーズ:攻撃者は何を考える?

レース系の典型的な穴は4パターンで考えると整理しやすいよ。
💰 仮説①:TOCTOU(Time-of-check / Time-of-use)
TOCTOUは、「確認した時点」と「実際に使う時点」の間にズレが生まれる問題です。残高確認、在庫確認、権限確認、クーポン利用可否などを確認した後、更新までの間に別の処理が割り込むと、不整合が起きることがあります。
🎟️ 仮説②:1回限定処理の重複実行
「1人1回」「1注文1回」「1アカウント1回」といった制約が、並列実行時にも本当に守られるかを確認します。クーポン、紹介特典、抽選応募、無料トライアル、ポイント付与などは、重複処理が起きやすい領域です。
📨 仮説③:一意制約の競合
ユーザー名、メールアドレス、注文番号、クーポン利用履歴など、本来一意であるべき値が、同時実行時にも一意に保たれるかを確認します。アプリ側のチェックだけに頼っていて、DB側に一意制約がない場合は危険です。
🔄 仮説④:状態遷移の競合
注文、決済、キャンセル、返金、発送、本人確認など、複数の状態を持つ処理では、同時実行によって矛盾した状態が成立しないかを確認します。「支払い済みなのにキャンセル済み」「返金済みなのにポイントが残る」といった不整合が典型です。
レースコンディションは、同時実行された複数の処理が同じ状態を読んでしまうことで起きます。攻撃手順そのものより、設計上「並列でも壊れないか」を確認することが重要です。

処理が1つずつなら問題なくても、同時に走ると壊れることがあるんだね…💸
🔬 検証フェーズ:どうやって確かめる?
検証では、実サービスに対して負荷をかけるのではなく、CTFやローカル検証環境で「同時実行されたときに状態が壊れないか」を確認します。重要なのは、処理の前後で残高・在庫・ポイント・ステータス・利用履歴が一貫しているかを見ることです。

CTFや許可された検証環境では、同じ操作を並列に実行したときの状態変化を見て、二重処理や不整合が起きないかを確認するよ📊
確認するときは、以下の観点で表にまとめると分かりやすくなります。
- 処理前の状態:残高、在庫、ポイント、ステータス、利用履歴
- 同時実行された操作:購入、出金、クーポン適用、応募、返金など
- 処理後の状態:数値やステータスに矛盾がないか
- DB制約・ログ:一意制約、処理済みフラグ、監査ログが残っているか
- 再実行時の挙動:同じ操作が複数回届いても安全か

ツールで一発検出というより、処理前後の状態を比べるのが大事なんだね🧪
⚔️ 攻撃フェーズ:CTFで見る典型パターン
ここでは実サービスに対して試せる手順ではなく、CTFやローカル検証環境でよく出る「考え方」だけを整理します。具体的な検証は、必ず自分の環境・CTF問題・許可されたラボ内で行ってください。

レースコンディションの代表パターンはこの3つで整理できるよ。
残高、ポイント、在庫などを扱う処理で、複数のリクエストが同じ「更新前の状態」を読んでしまい、二重消費や重複付与が発生しないかを確認するパターンです。
1回限りのクーポン、紹介特典、抽選応募、無料トライアルなどで、同時実行時にも「1回だけ」という制約がサーバー側で守られるかを確認するパターンです。
ユーザー名、メールアドレス、注文番号、処理済みフラグ、注文ステータスなどが、並列処理でもDBレベルで一貫して保たれるかを確認するパターンです。
CTF{parallel_requests_must_not_break_state}
レースコンディションの怖さは、単発の正常系テストでは見つかりにくいことです。防御では「1回だけ正しく動く」ではなく、同時に複数回呼ばれても壊れない設計を目指します。
🛡️ 防御フェーズ:どう守る?

レース対策の基本は「並列でも壊れない設計」にすること!🛡️
読み取り、判定、更新を別々に行うのではなく、必要に応じてDBトランザクション内で扱います。重要な行はロックし、読み取りから書き込みまでを一貫した処理として扱います。
購入、出金、返金、ポイント付与などの重要APIでは、同じ操作が複数回届いても一度だけ処理されるようにします。リクエストごとに一意のキーを持たせ、重複した場合はサーバー側で同じ結果を返す設計にします。
ユーザー名、メールアドレス、注文番号、クーポン利用履歴などの一意性は、アプリケーションコードだけでなく、DBスキーマ側のUNIQUE制約・CHECK制約でも守ります。
クーポン適用、ポイント付与、返金、出金、応募などは、同じ操作が複数回届いても一度だけ成功するように設計します。処理済みフラグ、一意制約、状態遷移チェックをサーバー側で管理します。
出金、返金、ポイント付与、クーポン適用、抽選応募、本人確認状態の変更などは、誰が・いつ・どの状態で実行したかを記録します。後から二重処理や不整合を追跡できるようにします。

「並列でも壊れない設計」が本物の堅牢性なんだね💪
🔑 あわせて見直したい基本対策
レースコンディションの直接対策ではありませんが、セキュリティ全体を見直す際に、パスワードの使い回しも同時に改善しておくと安心です。パスワード管理ツールを使って、サービスごとに異なるパスワードを管理しましょう。
※ 上記は他社サービスへのリンクです。購入は各自でご判断ください。
⚠️ よくある落とし穴
- 読み取り・判定・更新を分けて実装し、同時実行時の割り込みを考慮していない。
- アプリ層だけで重複チェックして、DBのUNIQUE制約やCHECK制約を省略している。
- レートリミットだけで安心し、並列実行への防御を考えていない。
- 「UI上は1回しか押せない」ことで安全だと思い込み、API側で二重処理を防いでいない。
- マイクロサービス間の整合性を結果整合性だけに任せ、途中状態の不整合を追跡できない。
- 楽観的ロックを導入したつもりで、versionカラムや更新条件の確認が不十分。
🧰 ツール早見表
レースコンディションは、攻撃ツールよりも「状態の変化を追う力」が重要です。補助ツール・資料としては、以下のようなものが役立ちます。
| ツール・資料 | 用途 | ひと言 |
|---|---|---|
| Burp Suite | リクエスト確認 | CTF・許可された診断で、処理の流れを確認する |
| DBトランザクションログ | 競合確認 | 同時実行時にどの順序で更新されたかを見る |
| 状態遷移図 | 業務フロー整理 | 許可される順序と禁止される順序を可視化する |
| 負荷テスト環境 | 再現確認 | 本番ではなく、隔離された検証環境で確認する |
| 監査ログ | 事後追跡 | 二重処理・重複付与・不整合を追跡する |
🎓 本気で学びたい人へ
Webセキュリティを「趣味」から「仕事」に変えたい方へ。🎓 ササエルはインフラエンジニアに特化したオンラインスクールで、セキュリティ設計の基礎から体系的に学べます。
📚 もっと深く学びたい人へ
体系的に攻撃と防御の両面を学びたいなら『ホワイトハッカー入門 第2版』が分かりやすい入口です📚
⚖️ 大事なお約束
この記事の手法は、必ず自分の環境か、許可されたCTF・脆弱性報奨金プログラム(HackerOne、Bugcrowd等)で試してください。他人のサービスに無断で攻撃を仕掛けるのは不正アクセス禁止法違反、立派な犯罪です。学んだ知識は守る側で活かしましょう🤝
📚 次に読みたい
- SSRF・LFI編|CTF思考フレームワーク #11
- ビジネスロジック編|CTF思考フレームワーク #13
- CORS・SOP編|CTF思考フレームワーク #10
- SSTI編|CTF思考フレームワーク #14
🧪 自分で検証してみる
レースコンディションの検証は、まずローカルPC上のDocker環境やCTF専用ラボで行うのがおすすめです。VPSを使う場合も、検証用ポートを外部公開せず、外部からアクセスできない構成にしてください。



