Bir Next.js API Rotasında Yarış Durumu (Race Condition)
Tek kullanımlık bir kupon yalnızca bir kez çalışmalıdır.
Ancak bu senaryoda, otuz kişi aynı anda kuponu kullanabilir.
Bu durum, bir "Time-of-Check Time-of-Use" (TOCTOU) yarış durumu (race condition) nedeniyle gerçekleşir.
Hata iki adımda meydana gelir:
- Adım: Sunucu, kullanım sayısını kontrol etmek için veritabanını okur.
- Adım: Sunucu, bu sayıyı artırmak için ikinci bir komut gönderir.
Eğer aynı anda birçok istek gönderirseniz, sunucu bunların hepsini bu iki adımın ortasında işler.
Birçok istek, sayı henüz sıfırken okuma yapar. Hepsi kontrolü geçer. Hepsi indirimi uygular. Hepsi sayacı artırır.
Sonuç mu? Tek bir kişi için tasarlanan bir kupon otuz kez kullanılır.
Kod incelemeleri sırasında bunu gözden kaçırmak kolaydır. Mantık, satır satır okunduğunda kusursuz görünür. Kusur, ancak hız ve eşzamanlılığı (concurrency) hesaba kattığınızda ortaya çıkar.
Nasıl düzeltilir:
Ayrı okuma ve yazma komutları kullanmayı bırakın. Bunun yerine, tek bir atomik işlem (atomic operation) kullanın.
Prisma'da, WHERE ifadesinde bir koşul ile updateMany kullanabilirsiniz:
• Veritabanı koşulu kontrol eder ve güncellemeyi tek bir hamlede gerçekleştirir. • Eğer sayı zaten sınıra ulaşmışsa, güncelleme anında başarısız olur. • Kontrol ve yazma arasına başka hiçbir istek sızamaz.
Diğer bir seçenek ise bir veritabanı işlemi (database transaction) kullanmaktır. Bu, siz işlemi bitirene kadar veriyi kilitler, böylece başka hiçbir istek veriye dokunamaz.
SQLite için tek bir güncelleme komutu en güvenilir yöntemdir.
Kendinize her zaman şunu sorun: İki istek aynı milisaniyede bu mantığa çarparsa ne olur?
Kaynak: https://dev.to/oopssec-store/racing-a-nextjs-api-route-coupon-abuse-with-prisma-and-sqlite-3gma