Konuyu Açan
#0
(Savunma Odaklı Teknik İnceleme – VIP)
Klasik race condition’lar tek sunucu/tek DB bağlamında düşünülürdü. Modern fintek/ödeme mimarilerinde ise risk büyüyor çünkü:
Bu ortamda yarış koşulu yalnız “thread bug” değil; iş kuralı (business logic) + tutarlılık (consistency) + idempotency problemi oluyor. PortSwigger bu sınıfı “iş mantığına yakın” bir zafiyet kategorisi olarak ele alır. PortSwigger
Bugcrowd, limit aşımını race condition’ların en yaygın etkilerinden biri olarak özetler: eşzamanlı işlemler, sistemin “tek sefer / tek limit” kuralını delmiş gibi davranmasına yol açabilir. Bugcrowd
Finansal örnek sınıfları (konsept):
Race condition çoğu zaman “kural var ama yanlış sırayla uygulanıyor” problemidir:
TOCTOU, MITRE’nin CWE-367 tanımında bu çekirdek fikirle açıklanır: kaynak durumu kontrol edildikten sonra kullanım anına kadar değişebilir. cwe.mitre.org
Finansal akışlar genelde şu üç aşamada kurgulanır:
Race condition’lar özellikle şu hatalarda çıkar:
OWASP Testing Guide, race condition’ların test edilmesinin zor olduğuna ve kod incelemede “eşzamanlılık” bölgelerinin aranması gerektiğine dikkat çeker. owasp.org
Ağ hatası/timeout sonrası aynı isteğin yeniden gönderilmesi normaldir. Eğer sistem idempotent değilse, aynı işlem iki kez işlenebilir.
Stripe, idempotency yaklaşımını “aynı işlemin yanlışlıkla iki kez yapılmasını” önlemek için bir temel best practice olarak anlatır. docs.stripe.com+1
SQL tarafında izolasyon seviyesi ve kilitleme stratejisi, yarışları ya önler ya da görünmez kılar:
DynamoDB gibi sistemlerde “optimistic locking / condition check” ile eşzamanlı güncellemelerde kural korunur (doğru tasarlanırsa). AWS, yüksek eşzamanlılıkta koşullu yazma (conditional writes) desenlerini anlatır. Amazon Web Services, Inc.
PortSwigger ve OWASP içerikleri, bu sınıfın “iş mantığı” ile iç içe olduğunu ve klasik imzalarla kaçabileceğini vurgular. PortSwigger+1
Hedef: Check ile Commit arasındaki boşluğu kapatmak (TOCTOU’yu yok etmek). cwe.mitre.org
Stripe’ın idempotent request dokümantasyonu bu modelin temelini açıklar. docs.stripe.com+1
PostgreSQL’in izolasyon seviyesi dokümantasyonu ve InnoDB’nin transaction modeli bu kararların temel referansıdır. PostgreSQL+1
AWS’nin DynamoDB koşullu yazma anlatımı bu deseni örnekler. Amazon Web Services, Inc.
1) Neden “2.0”?
Klasik race condition’lar tek sunucu/tek DB bağlamında düşünülürdü. Modern fintek/ödeme mimarilerinde ise risk büyüyor çünkü:
- Mikroservisler + event-driven akışlar
- Dağıtık cache/queue kullanımı
- Çoklu ödeme sağlayıcıları (PSP), tekrar deneme (retry) mekanikleri
- “Eventually consistent” veri ve farklı doğrulama katmanları
Bu ortamda yarış koşulu yalnız “thread bug” değil; iş kuralı (business logic) + tutarlılık (consistency) + idempotency problemi oluyor. PortSwigger bu sınıfı “iş mantığına yakın” bir zafiyet kategorisi olarak ele alır. PortSwigger
2) Finansal Sistemlerde Tipik Etki: “Limit Overrun” ve “Logic Bypass”
2.1 Limit Overrun (Limit Aşımı)
Bugcrowd, limit aşımını race condition’ların en yaygın etkilerinden biri olarak özetler: eşzamanlı işlemler, sistemin “tek sefer / tek limit” kuralını delmiş gibi davranmasına yol açabilir. Bugcrowd
Finansal örnek sınıfları (konsept):
- Günlük/haftalık transfer limiti
- Kupon/indirim kullanım limiti
- Cüzdan yükleme limiti
- Tek seferlik iade/refund kuralı
- “1 kullanıcı = 1 promosyon” gibi kurallar
2.2 Logic Bypass (İş Kuralı Atlama)
Race condition çoğu zaman “kural var ama yanlış sırayla uygulanıyor” problemidir:
- Check (uygun mu?) ile Use/Commit (uygula) arasında zaman boşluğu (TOCTOU)
- Bir servis “uygun” derken diğeri state’i değiştirmiş olur
TOCTOU, MITRE’nin CWE-367 tanımında bu çekirdek fikirle açıklanır: kaynak durumu kontrol edildikten sonra kullanım anına kadar değişebilir. cwe.mitre.org
3) Zafiyet Nerede Doğar? “Kontrol – Rezerv – Kesinleştir” Ayrışması
Finansal akışlar genelde şu üç aşamada kurgulanır:
- Kontrol (Check): bakiye/limit/uygunluk
- Rezerv (Reserve/Hold): kaynak ayırma (bakiye düşme/hold)
- Kesinleştir (Commit/Settle): nihai kayıt ve dış sistemlerle mutabakat
Race condition’lar özellikle şu hatalarda çıkar:
- Check ile Commit aynı atomik işlem değilse
- “Rezerv” yoksa veya rezerv idempotent değilse
- Aynı “işlem kimliği” (transaction id) iki kez işlenebiliyorsa
- Cache/DB arasında “kaynak gerçekliği” ayrışıyorsa
OWASP Testing Guide, race condition’ların test edilmesinin zor olduğuna ve kod incelemede “eşzamanlılık” bölgelerinin aranması gerektiğine dikkat çeker. owasp.org
4) Modern Sistemlerde “Race Condition 2.0”ı Büyüten Tuzaklar
4.1 Retry (Tekrar Deneme) ve “Çifte İşleme”
Ağ hatası/timeout sonrası aynı isteğin yeniden gönderilmesi normaldir. Eğer sistem idempotent değilse, aynı işlem iki kez işlenebilir.
Stripe, idempotency yaklaşımını “aynı işlemin yanlışlıkla iki kez yapılmasını” önlemek için bir temel best practice olarak anlatır. docs.stripe.com+1
4.2 Dağıtık Mimari ve Tutarlılık Farkları
- “Limit servisi” ayrı, “ledger/bakiye” ayrı, “kampanya” ayrı ise
- Her servis kendi state’ine göre karar veriyorsa
tek bir “gerçek” kaybolur → yarış yüzeyi artar.
4.3 Yanlış Transaction Isolation / Locking
SQL tarafında izolasyon seviyesi ve kilitleme stratejisi, yarışları ya önler ya da görünmez kılar:
- PostgreSQL, “Serializable” seviyesini eşzamanlı işlemlerin tek tek çalıştırılmış gibi etki üretmesi hedefiyle tanımlar. PostgreSQL
- MySQL InnoDB’nin izolasyon seviyeleri ve davranışları da bu bağlamda kritik tasarım girdisidir. MySQL Geliştirici Bölgesi+1
4.4 NoSQL / Event Store Senaryoları
DynamoDB gibi sistemlerde “optimistic locking / condition check” ile eşzamanlı güncellemelerde kural korunur (doğru tasarlanırsa). AWS, yüksek eşzamanlılıkta koşullu yazma (conditional writes) desenlerini anlatır. Amazon Web Services, Inc.
5) Tespit (Detection): Finansal Risk İçin En Faydalı Sinyaller
5.1 “Çifte Kayıt” ve Tutarsız Mutabakat
- Aynı kullanıcı/aynı zaman diliminde “benzer” işlem kayıtlarının çoğalması
- Ledger (ana kayıt) ile “limit”/“kampanya” kayıtlarının uyuşmaması
- Refund/chargeback anomali oranında artış
5.2 Idempotency Drift
- Aynı işlem kimliğiyle (order_id / payment_intent_id benzeri) birden fazla “başarılı” sonuç
- Timeout sonrası “yeniden deneme” sayısı artarken finansal sonuçların iki katına çıkması
5.3 Anomali Skorları
- Normal kullanıcı davranışından sapma (kısa sürede aşırı işlem denemesi)
- Limit doluyken “başarılı” görünen işlem sayısı
- Stok/kupon gibi kotalı nesnelerde negatif değerler / beklenmeyen sıçramalar
PortSwigger ve OWASP içerikleri, bu sınıfın “iş mantığı” ile iç içe olduğunu ve klasik imzalarla kaçabileceğini vurgular. PortSwigger+1
6) Önleme (Mitigation): “Kesin Çözüm” Katmanları
6.1 Atomiklik: Tek Kaynakta Tek Gerçek
- Limit/bakiye değişimi tek atomik işlem olarak tasarlanmalı
- “Check-then-update” yerine DB/ledger üzerinde atomik update + kural
Hedef: Check ile Commit arasındaki boşluğu kapatmak (TOCTOU’yu yok etmek). cwe.mitre.org
6.2 Idempotency Zorunlu
- Her finansal işlem “idempotency key / transaction id” ile tekilleştirilmeli
- Aynı anahtar tekrar gelirse sistem aynı sonucu döndürmeli, ikinci kez işlememeli
Stripe’ın idempotent request dokümantasyonu bu modelin temelini açıklar. docs.stripe.com+1
6.3 Doğru İzolasyon ve Kilitleme Stratejisi
- Kritik transfer/limit güncellemelerinde uygun transaction izolasyonu
- “Serialization failure” gibi durumlarda güvenli retry stratejisi (kontrollü)
PostgreSQL’in izolasyon seviyesi dokümantasyonu ve InnoDB’nin transaction modeli bu kararların temel referansıdır. PostgreSQL+1
6.4 Dağıtık Sistemlerde Koşullu Güncellemeler
- Versiyon alanı / optimistic locking
- Koşullu yazma (expected version) başarısızsa işlemi reddet/yeniden dene
AWS’nin DynamoDB koşullu yazma anlatımı bu deseni örnekler. Amazon Web Services, Inc.
6.5 İş Kuralı Sertleştirme
- “Rezerv” (hold) olmadan “kesinleştirme” yapma
- Kupon/limit gibi kotaları tek yetkili servis üzerinden yönet
- Event tüketicilerinde “exactly-once” varsayma → dedup uygula
