utsuroi race labsLab 01 / 5 — Practitioner
01

クーポンコードの並行使用 — TOCTOU

Race condition allowing double coupon redemption

うつろい EC で「初回限定 50% OFF」キャンペーン。クーポンコード FIRST50 は1人1回限りのはず。サーバの実装は:

function redeemCoupon($code, $order_id, $user_id) {
    // ① 未使用チェック
    $coupon = SELECT * FROM coupons WHERE code = $code AND used = false;
    if (!$coupon) return error('使用済み');
    
    // ② 注文に割引適用(数百ミリ秒かかる処理)
    apply_discount($order_id, $coupon->amount);
    
    // ③ クーポンを使用済みに
    UPDATE coupons SET used = true WHERE id = $coupon->id;
}

① と ③ が分離している間に並行リクエストが入ると、両方が「未使用」と判定されて二重適用されます。

1リクエストで1回しか使えないはずの FIRST50 クーポンを、並行リクエストで複数の注文に適用してください。

FIRST50 クーポン

CODEFIRST50
DISCOUNT50% off
USEDfalse
USED BY(未使用)
適用注文0件

攻撃シナリオ

2つのリクエストを同時に発射して、両方を「未使用」と判定させてクーポンを二重適用する。

サーバ処理ログ

(まだ実行していません)