5 dk okuma
Giriş
Solidity reentrancy güvenliği, bir akıllı sözleşmenin dış çağrı sırasında kontrolü başka bir kontrata devretmesinden doğan en kritik tasarım konularından biridir. Bir fonksiyon Ether gönderdiğinde, token standardı üzerinden hook tetiklediğinde veya başka bir kontratı çağırdığında karşı taraf, ilk işlem tamamlanmadan aynı kontrata yeniden girebilir. Eğer bakiye, hak sahipliği veya işlem durumu dış çağrıdan sonra güncelleniyorsa aynı hak birden fazla kez kullanılabilir.
Solidity’nin güncel güvenlik dokümantasyonu bu riske karşı Checks-Effects-Interactions yaklaşımını temel savunmalardan biri olarak önerir: önce koşullar doğrulanır, sonra kontratın state’i güncellenir ve dış etkileşim en sona bırakılır. OpenZeppelin ise ReentrancyGuard ile kritik fonksiyonlara ek bir tekrar giriş kilidi sağlar. Güvenli tasarımda bu iki yaklaşım rakip değil, birbirini tamamlayan katmanlardır.
Checks-Effects-Interactions, ReentrancyGuard ve saldırgan kontrat testlerini çalışan Solidity örneğiyle inceleyin.
İçindekiler
- Reentrancy saldırısının kontrol akışını anlayın
- Checks-Effects-Interactions desenini varsayılan hale getirin
- ReentrancyGuard'ı doğru entry point'lerde kullanın
- Ödeme akışlarında pull modelini değerlendirin
- Cross-function ve cross-contract reentrancy riskini unutmayın
- Saldırgan kontratla otomatik test yazın
- Üretim öncesi güvenlik ve operasyon kontrolü uygulayın
- Hızlı Bakış
- Sonuç
- Güvenilir Araştırma Kaynakları
1. Reentrancy Saldırısının Kontrol Akışını Anlayın
Reentrancy'nin özü, dış çağrının yalnızca veri göndermemesi; aynı zamanda yürütme kontrolünü karşı tarafa vermesidir. Bir withdraw fonksiyonu önce kullanıcıya Ether gönderip bakiyeyi daha sonra sıfırlıyorsa alıcı kontratın receive veya fallback akışı ilk withdraw tamamlanmadan yeniden withdraw çağırabilir. İlk çağrı henüz bakiyeyi düşürmediği için ikinci çağrı aynı eski state'i görür.
Bu nedenle risk analizi yalnızca payable fonksiyonlarla sınırlı olmamalıdır. Solidity dokümantasyonu reentrancy'nin Ether transferinden başka kontrat çağrılarında da oluşabileceğini özellikle vurgular. ERC token etkileşimleri, callback kullanan protokoller, oracle adaptörleri ve çok kontratlı iş akışları da aynı kontrol devri mantığıyla değerlendirilmelidir.
2. Checks-Effects-Interactions Desenini Varsayılan Hale Getirin
Checks-Effects-Interactions, fonksiyon akışını üç bölüme ayırır. Checks aşamasında yetki, bakiye, limit ve parametre koşulları doğrulanır. Effects aşamasında kontratın kendi state'i nihai sonuca mümkün olduğunca yaklaştırılır. Interactions aşamasında dış kontrat çağrıları yapılır. Böylece karşı taraf yeniden giriş yapmaya çalışsa bile kritik state çoktan güncellenmiş olur.
Bu desenin gücü basitliğidir; ancak mekanik bir sıralama kuralı olarak uygulanmamalıdır. Birden fazla mapping, toplam bakiye veya muhasebe değişkeni birlikte değişiyorsa dış çağrıdan önce bütün invariant'ların tutarlı hale gelmesi gerekir. Yalnızca tek bir bakiyeyi erken sıfırlamak, ilişkili başka state eski değerinde kalıyorsa yeterli olmayabilir.
3. ReentrancyGuard'ı Doğru Entry Point'lerde Kullanın
OpenZeppelin Contracts 5.x içindeki ReentrancyGuard, nonReentrant modifier'ı ile korunan fonksiyonlara iç içe tekrar giriş yapılmasını engeller. Özellikle para çekme, claim, redeem, settlement veya harici protokolle değer transferi yapan entry point'lerde güçlü bir ikinci savunma katmanıdır. Bununla birlikte modifier, kötü state sıralamasını düzeltmez; CEI deseninin yerine geçmez.
Ayrıca aynı guard'ı kullanan iki nonReentrant fonksiyonun birbirini doğrudan çağırması desteklenmez. OpenZeppelin'in önerdiği yaygın çözüm, dışarı açık nonReentrant entry point'i küçük tutup asıl iş mantığını private veya internal fonksiyona taşımaktır. Böylece erişim yüzeyi açık kalırken guard'ın tek kilit modeliyle çakışma azaltılır.
Pratik sıra nettir: dış çağrı noktalarını bulun, kontrolleri başa alın, state'i dış etkileşimden önce güvenli hale getirin, kritik entry point'lerde guard kullanın, ödeme modelini gerekirse pull akışına taşıyın ve saldırgan kontratla yeniden giriş testini otomatikleştirin.
Sonuç
Solidity reentrancy güvenliği tek bir güvenlik aracına indirgenemez. Checks-Effects-Interactions state sıralamasını güvenli hale getirir; ReentrancyGuard kritik giriş noktalarında tekrar çağrıyı sınırlar; pull modeli dış alıcı bağımlılığını azaltabilir; saldırgan kontrat testleri ise tasarım varsayımlarını gerçek kontrol akışı altında doğrular.
Bu konu, daha önce yayımlanan Solidity Upgradeable Smart Contract rehberi ile aynı Web3 güvenlik kümesini tamamlar. Upgrade yetkisi ve storage uyumluluğu kontratın yaşam döngüsünü korurken, reentrancy savunması çalışma anındaki state bütünlüğünü korur. İki yaklaşım birlikte ele alındığında daha sürdürülebilir bir smart contract güvenlik modeli oluşur.
Güvenilir Araştırma Kaynakları
Solidity - Security Considerations - Reentrancy ve Checks-Effects-Interactions için resmi Solidity güvenlik rehberi.
OpenZeppelin Contracts 5.x - ReentrancyGuard - nonReentrant koruması ve güncel utility güvenlik bileşenleri.
OpenZeppelin Contracts - güvenli smart contract geliştirme için güncel kütüphane ve kullanım ilkeleri.

