概要
レースコンディション(Race Condition:競合状態)は、複数の処理が同時に同一の資源(ファイル・共有メモリ・DBレコード等)にアクセスする際、処理の実行順序やタイミングによって結果が変わってしまう現象です。攻撃者はこのタイミングのずれを意図的に狙い、想定外の状態を作り出して権限昇格・二重実行・データ破壊を引き起こします。代表例がTOCTOU(Time-of-Check to Time-of-Use)脆弱性で、「確認した時点」と「使用する時点」の間に対象が変化することを悪用します。バッファオーバーフロー等のメモリ安全性の問題とは異なり、並行処理・タイミングに起因する脆弱性として、SC試験の午前II・午後の両方で問われる分野です。
仕組みと動作原理
レースコンディションの基本原理
複数のスレッド・プロセス・リクエストが共有資源に対して「読み取り→判断→書き込み」のような一連の処理を行う場合、その間に別の処理が割り込むと、想定していた前提が崩れます。
本来期待する順序(処理Aが単独で実行される場合):
処理A: 残高を確認(1000円)→ 1000円分の決済を実行 → 残高を0円に更新
競合が起きた場合(処理Aと処理A'がほぼ同時に実行):
処理A : 残高を確認(1000円)
処理A': 残高を確認(1000円)← まだ更新前なので同じ1000円が見える
処理A : 1000円分の決済を実行 → 残高を0円に更新
処理A': 1000円分の決済を実行 → 残高を0円に更新
結果:1000円の残高から2000円分の決済が通ってしまう
この「確認(Check)」と「使用(Use)」の間に割り込みが発生する構造がTOCTOUの本質です。
TOCTOU脆弱性の典型例
| パターン | 仕組み |
|---|---|
| ファイル属性のTOCTOU | 権限チェック(access()等)でファイルの所有者・権限を確認した直後、実際にオープンするまでの間にファイルが差し替えられる |
| シンボリックリンク攻撃 | 一般ユーザ権限で書き込み可能な一時ディレクトリで、チェック対象のファイルを攻撃者がシンボリックリンクに差し替え、特権プロセスに機密ファイルを上書きさせる |
| ファイルロックの競合 | ロック取得前に内容を確認し、ロック取得後に別プロセスが書き換えていた内容を信頼してしまう |
根本原因: チェックと使用が2つの別々の操作(非アトミック)になっており、その間に他の主体が対象を変更できる時間の隙(ウィンドウ)が存在すること。
Webアプリケーションにおける二重実行攻撃
Webアプリでは、同一のリクエストを短時間に複数回・同時に送信することで、サーバ側の「確認→更新」処理の間隙を突く攻撃が典型的です。
| 攻撃対象 | 手口 | 影響 |
|---|---|---|
| クーポン・ポイントの二重取得 | 同一クーポンの適用リクエストを並列送信し、利用済みフラグの更新前に複数回処理させる | ポイント・割引の不正取得 |
| 在庫の二重予約(オーバーセル) | 残り1点の商品に対する購入リクエストを同時送信し、在庫チェックをすり抜けて複数人に販売成立させてしまう | 在庫過剰販売・出荷トラブル |
| 口座残高の二重出金 | 送金・出金APIを並列で呼び出し、残高チェックの前提が崩れた状態で複数回の出金を成立させる | 不正な資金流出 |
| アカウント作成の重複 | 一意性チェック(メールアドレス重複確認)と登録処理の間を突き、同一メールで複数アカウントを作成 | なりすまし・不正利用の温床 |
なぜ発生するのか(非アトミック性)
「在庫を確認する」「在庫を1減らす」という2つの操作がデータベース上で別々のSQL文(SELECTしてからUPDATEする等)として実行されると、その間に他のトランザクションが割り込む余地が生まれます。単一のCPU命令やDBのアトミック操作として不可分に実行されない限り、並行処理下では常にこの種の競合が起こり得ます。
対策
| 対策 | 説明 |
|---|---|
| アトミック操作の利用 | 「確認と更新」を1つの不可分な操作にまとめる(例: UPDATE inventory SET stock = stock - 1 WHERE stock > 0 のように条件付き更新を1文で行う) |
| 排他制御(ロック) | 対象資源にロックをかけ、一連の処理が完了するまで他の処理からのアクセスを禁止する(悲観的ロック) |
| 楽観的ロック(バージョン管理) | 読み取り時のバージョン番号を保持し、更新時にバージョンが変わっていないかを検証してから書き込む |
| 冪等性(Idempotency)の設計 | 同一リクエストが複数回届いても結果が1回分と同じになるよう、冪等性キー(Idempotency Key)等でリクエストを一意に管理する |
| データベースの一意制約・トランザクション分離レベル | UNIQUE制約や適切な分離レベル(SERIALIZABLE等)で二重登録・二重更新自体をDB側で防ぐ |
| シンボリックリンク攻撃対策 | チェックと使用を同一のファイルディスクリプタに対して行う(open() してから fstat() で確認する等、名前ではなくハンドルで操作する) |
SC試験での頻出ポイント
- TOCTOUの定義:「チェック時点」と「使用時点」の間に対象が変化することを悪用する脆弱性
- 非アトミック性が根本原因:確認と更新が分離された処理は競合状態を生みやすい
- シンボリックリンク攻撃の仕組み:特権プロセスがチェック後にファイル参照先を差し替えられて機密ファイルを上書き・漏えいさせられる
- Webアプリの二重実行攻撃:同時リクエストによる在庫・ポイント・残高の不正取得(オーバーセル等)
- 対策の中心はアトミック操作とロック:条件付き更新・排他制御・冪等性設計による解決
よくある誤問・ひっかけパターン
誤り① 「レースコンディションはマルチスレッドプログラムだけの問題である」→ 誤。Webアプリのように複数のリクエスト(プロセス・接続)が同一のDBレコードに同時アクセスする場合も同様の競合状態が発生します。単一スレッドかどうかは本質ではなく、共有資源への並行アクセスがあるかどうかが問題です。
誤り② 「トランザクションを使えばレースコンディションは自動的に防げる」→ 状況次第。トランザクションを使っていても、分離レベルが低い(READ COMMITTED等)場合は「確認」と「更新」の間に他のトランザクションの変更が割り込む余地が残ります。適切な分離レベルの選択やSELECT FOR UPDATE等の明示的なロックが必要です。
誤り③ 「リクエストの発生確率が低いので実運用でTOCTOUや二重実行攻撃が成立することは稀」→ 誤。攻撃者は意図的に同時刻に大量のリクエストを送信するツールを用いてタイミングの窓を確実に突くため、偶発的な事故よりもむしろ悪用されやすい脆弱性です。
関連用語
- バッファオーバーフローとメモリ安全性 — 同じくC言語等で顕在化しやすい脆弱性だが、こちらはメモリ境界、レースコンディションは並行処理のタイミングが原因という違いがある
- セキュアコーディング — アトミック操作・排他制御を含む安全な実装規約
- IDOR(安全でない直接オブジェクト参照) — アクセス制御の不備という点で関連し、認可チェックと利用のタイミングのずれが問題になる場合がある
- APIセキュリティ — 冪等性キー等、API設計における二重実行対策の実務的な観点
重要キーワード
| 用語 | 説明 |
|---|---|
| レースコンディション | 複数処理が同一資源に同時アクセスすることで結果が処理順序に依存してしまう競合状態 |
| TOCTOU | チェック時点と使用時点の間に対象が変化することを悪用する脆弱性 |
| シンボリックリンク攻撃 | チェックと使用の間にファイル参照先を差し替え特権プロセスに不正操作させる攻撃 |
| アトミック操作 | 確認と更新等の一連の処理を不可分な単位として実行する仕組み |
| 冪等性(Idempotency) | 同一リクエストが複数回届いても結果が1回分と変わらない性質 |
| 楽観的ロック | バージョン番号等で更新時の競合を検出する排他制御方式 |