概要

レースコンディション(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()等)でファイルの所有者・権限を確認した直後、実際にオープンするまでの間にファイルが差し替えられる
シンボリックリンク攻撃一般ユーザ権限で書き込み可能な一時ディレクトリで、チェック対象のファイルを攻撃者がシンボリックリンクに差し替え、特権プロセスに機密ファイルを上書きさせる
ファイルロックの競合ロック取得前に内容を確認し、ロック取得後に別プロセスが書き換えていた内容を信頼してしまう
TOCTOU脆弱性(シンボリックリンク攻撃)の流れ
1
特権プロセス
対象ファイルの権限・所有者をチェック(Check)
この時点では正規の安全なファイル
2
攻撃者
チェックと使用の間の一瞬を狙いファイルをシンボリックリンクに差し替え
攻撃者が指定した任意のファイルを指すリンクに変更
3
特権プロセス
チェック結果を信頼したまま対象ファイルを使用(Use)
実際には攻撃者が用意した別ファイルを開いてしまう
4
結果
特権プロセスの権限で機密ファイルの上書き・読み取りが発生

根本原因: チェックと使用が2つの別々の操作(非アトミック)になっており、その間に他の主体が対象を変更できる時間の隙(ウィンドウ)が存在すること。

Webアプリケーションにおける二重実行攻撃

Webアプリでは、同一のリクエストを短時間に複数回・同時に送信することで、サーバ側の「確認→更新」処理の間隙を突く攻撃が典型的です。

攻撃対象手口影響
クーポン・ポイントの二重取得同一クーポンの適用リクエストを並列送信し、利用済みフラグの更新前に複数回処理させるポイント・割引の不正取得
在庫の二重予約(オーバーセル)残り1点の商品に対する購入リクエストを同時送信し、在庫チェックをすり抜けて複数人に販売成立させてしまう在庫過剰販売・出荷トラブル
口座残高の二重出金送金・出金APIを並列で呼び出し、残高チェックの前提が崩れた状態で複数回の出金を成立させる不正な資金流出
アカウント作成の重複一意性チェック(メールアドレス重複確認)と登録処理の間を突き、同一メールで複数アカウントを作成なりすまし・不正利用の温床
単一リクエスト処理 と 並列(二重実行)攻撃 の比較
通常の単一リクエスト 並列送信による二重実行攻撃
リクエスト数
1件ずつ順番に処理
同一操作を同時に複数送信
在庫/残高チェック
チェック時点の値が正しく反映される
更新前の同じ値を複数リクエストが参照
更新処理
1回だけ実行され整合性が保たれる
複数回実行され整合性が崩れる
結果
意図通りの1回分の処理
在庫のオーバーセル・ポイントの二重取得等

なぜ発生するのか(非アトミック性)

「在庫を確認する」「在庫を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や二重実行攻撃が成立することは稀」→ 。攻撃者は意図的に同時刻に大量のリクエストを送信するツールを用いてタイミングの窓を確実に突くため、偶発的な事故よりもむしろ悪用されやすい脆弱性です。

関連用語

重要キーワード

用語説明
レースコンディション複数処理が同一資源に同時アクセスすることで結果が処理順序に依存してしまう競合状態
TOCTOUチェック時点と使用時点の間に対象が変化することを悪用する脆弱性
シンボリックリンク攻撃チェックと使用の間にファイル参照先を差し替え特権プロセスに不正操作させる攻撃
アトミック操作確認と更新等の一連の処理を不可分な単位として実行する仕組み
冪等性(Idempotency)同一リクエストが複数回届いても結果が1回分と変わらない性質
楽観的ロックバージョン番号等で更新時の競合を検出する排他制御方式