Reentrancy saldırıları, Ethereum ve EVM uyumlu zincirlerdeki akıllı kontrat güvenliğine yönelik en kötü şöhretli ve kalıcı tehditlerden biri olmaya devam ediyor. Yıllardır süren endüstri çabalarına rağmen, yeni protokoller hâlâ reentrancy zafiyetleriyle karşılaşıyor ve bu da milyonlarca dolara varan ciddi mali kayıplara yol açıyor. Bu saldırılar genellikle dış çağrıların ve token transferlerinin yaygın olduğu DeFi kredi, staking ve köprü (bridge) sözleşmelerinde ortaya çıkıyor.
Bu yazıda, bir reentrancy saldırısının mekaniklerini inceliyor, tipik zayıf kontrat kalıplarını tespit ediyor ve test edilmiş savunma yöntemlerini paylaşıyoruz. Soken’de yaptığımız 255’ten fazla akıllı kontrat denetimi analizinden hareketle, Solidity’deki incelikli kodlama uygulamaları ve kapsamlı test süreçlerinin reentrancy tehditlerini nasıl engellediğini vurguluyoruz. Ayrıca delegatecall kötüye kullanımı ve flash loan taktikleri gibi ilişkili risklere de değinerek ciddi her Web3 geliştiricisi veya güvenlik denetçisinin anlaması gereken kapsamlı bir perspektif sunuyoruz.
Reentrancy Saldırısı Nedir ve Akıllı Kontratları Nasıl Sömürür?
Reentrancy saldırısı, kötü niyetli bir kontratın, hedef kontratın fonksiyonunun ilk yürütmesi tamamlanmadan önce tekrar tekrar aynı fonksiyonu çağırarak, söz konusu kontratın tutarsız durumundan faydalanmasıdır.
Pratikte bir reentrancy zafiyeti, kontrat içindeki kötü sıralanmış durum değişiklikleri ve dış çağrılar sonucu ortaya çıkar. Kontrat, ETH veya tokenleri call ya da transfer ile güvenilmeyen bir adrese gönderdiğinde, o alıcı reentrancy fonksiyonunu durum değişkenleri güncellenmeden önce tekrar çağırabilir. Bu sayede saldırgan fonksiyon mantığını beklenmedik biçimde manipüle eder ya da fonları boşaltır.
Örneğin, 2016’daki meşhur DAO saldırısı, reentrancy açığından yararlanılarak yaklaşık 60 milyon doların çalınmasıyla sonuçlanmıştır — önemli bir uyarı niteliğinde. O tarihten beri, endüstri, temel hatanın kontrat bakiyesinin veya durumunun dış çağrılar sonrasında güncellenmesi olduğunu tespit etti; bu da saldırganın istismar ettiği tutarsız bir durum penceresi yaratıyor.
Soken denetimleri uzman görüşü: “Son DeFi güvenlik denetimimizin %40’ından fazlasında reentrancy kalıpları çeşitli biçimlerde, sıklıkla vekil kontratlar veya katmanlı çağrılar içeren ince varyasyonlarla gözlemlendi. Bunları tespit etmek, tek bir kontrat incelemesinin ötesinde kapsamlı kontratlar arası çağrı analizlerini gerektiriyor.”
Reentrancy Zafiyetlerine Yol Açan Yaygın Solidity Kalıpları
Reentrancy zafiyetleri genellikle şu işlem sırasından kaynaklanır: kontrat, kendi iç durum değişkenlerini güncellemeden önce dış çağrılarda bulunur (örneğin ETH transferleri veya token çağrıları).
En kötü örnek olan kalıp şöyle görünür:
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount;
}
Burada call.value() kullanılarak yapılan dış çağrı, kullanıcının bakiyesi düşürülmeden önce gerçekleşir. Bu sırada saldırganın fallback fonksiyonu, withdraw() fonksiyonunu yineleyerek tetikleyebilir ve bakiye güncellenmeden fonları boşaltabilir.
Riskli başlıca yapılar şunlardır:
- Durum güncellenmeden önce dış çağrılar: Bakiyeleri güncellemeden önce ETH veya token gönderimi.
callveyasendkullanımı önlem olmadan: Düşük seviye fonksiyonlarla yapılan dış çağrılar, kontrol ve doğrulamalardan kaçabilir, fallback fonksiyonları çalıştırabilir.- Reentrancy koruma mekanizması olmaması: Mutex ya da kilitleme mekanizmasının yokluğu.
- Delegatecall içeren karmaşık çağrı zincirleri: Çağrılan kontratlar içindeki dış çağrılar dolaylı olarak reentrancy açığı yaratabilir.
Öte yandan, daha güvenli kalıp ise işlemi tersine çevirir:
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount; // durum önce güncellenir
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
Solidity’de Reentrancy Saldırılarına Karşı Önlemler: En İyi Uygulamalar ve Araçlar
Reentrancy’ye karşı en etkili savunma, dış çağrılardan önce durum değişkenlerini güncellemek ve açık reentrancy koruma kalıplarını kullanmaktır.
Standart azaltma teknikleri:
-
Checks-Effects-Interactions Kalıbı:
Her zaman önce iç durumu güncelleyin, ardından dış çağrılar yapın. Böylece dış çağrılar sırasında tutarsız durum minimize edilir. -
Reentrancy Koruyucuları / Mutexler:
OpenZeppelin’inReentrancyGuard’ı basit bir mutex kullanarak iç içe çağrıları engeller. Kullanımı şu şekildedir:
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureContract is ReentrancyGuard {
mapping(address => uint256) balances;
function withdraw(uint256 amount) public nonReentrant {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
}
-
Dış Çağrıları Sınırlayın:
Kritik fonksiyonlarda transfer veya dış işlemleri minimuma indirin; kullanıcıların fonları manuel çektiği pull ödeme modellerini tercih edin. -
Statik Analiz ve Otomatik Araçlar:
Slither gibi araçlar ile Soken’in kendi denetim çerçevesi reentrancy’yi işaretler. -
En Güncel Solidity Versiyonlarını ve Özelliklerini Kullanın:
Solidity 0.8+ ile dahili taşma kontrolleri geliyor, ancak reentrancy riski devam ediyor; bu yüzden kod güvenliği ile beraber tasarım kalıplarını da uygulamak şarttır.
Soken metodolojisi: Denetimlerimiz el ile tehdit modellemesi, sembolik yürütme ve fuzz testi entegre eder. Bu, karmaşık reentrancy akışlarını genellikle genel tarayıcıların kaçırdığı şekilde yakalar.
Reentrancy Sömürülerinin Gerçek Hayat Örnekleri ve Etkileri
Reentrancy saldırıları farkındalığın artmasına rağmen yaygın kalmaya devam ediyor. Aşağıda önemli hacklerin çeşitliliğini ve maliyetlerini gösteren karşılaştırma tablosu bulunmaktadır:
| Olay | Tarih | Kayıp Miktarı | Kullanılan Kalıp | Ana Ders |
|---|---|---|---|---|
| The DAO Hack | 2016-06 | ~60 milyon $ | splitDAO teklifinde reentrancy | Dış çağrıdan önce durum güncellenmeli |
| The Lendf.Me Hack | 2020-04 | 25 milyon $+ | Flash loan destekli reentrancy | Reentrancy koruma + flash loan direnci birleştirilmeli |
| Euler Finance Hack | 2023-03 | 197 milyon $ | Katmanlı reentrancy + delegatecall | Karmaşık çağrı zincirleri riski artırıyor |
| Son DeFi Köprü Hacki | 2025-11 | 15 milyon $ | Token transferinde reentrancy | Kontratlar arası etkileşimler denetlenmeli |
Not: Soken denetimleri, özellikle kontratlararası çağrılar ve fallback fonksiyonlarını tetikleyebilen token standartları etrafında katmanlı güvenliği vurgular.
Delegatecall ve Flash Loan Vektörleri: Reentrancy Risklerini Büyütmek
Delegatecall, çağrının kontratın kendi bağlamında kod yürütmesini sağlar, bu da reentrancy riskini gizleyebilir ve saldırı yüzeyini genişletebilir, özellikle flash loanlarla birleştiğinde.
Reentrancy saldırıları genellikle flash loanları kullanarak sermayeyi maksimize etmeye çalışır:
- Flash loanlar tek işlem içinde büyük likidite sağlar.
- Saldırgan, flash loan fonlarını kullanarak, borç geri ödenmeden önce protokol likiditesini tekrar tekrar reentrancy çağrısıyla boşaltır.
- Delegatecall kullanımı, dış ve güvenilmeyen kodun kontrat durumunu değiştirmesine veya yeniden girişlere izin vermesine yol açabilir.
Güvenlik değerlendirmesi: “Soken deneyiminde, reentrancy savunması tek kontratlarla sınırlı kalmamalı, aynı zamanda protokol genelinde tasarımla bütünleşmeli — özellikle delegatecall ve flash loan birlikte kullanıldığında. Kontratlar reentrancy koruyucularını giriş doğrulama ve flash loan’a özgü kontrollerle (kredi limiti, yineleyici çağrı sınırları) birleştirmeli.”
Karşılaştırma Tablosu: Yaygın Reentrancy Önleme Teknikleri
| Teknik | Açıklama | Avantajlar | Dezavantajlar | Kullanım Alanı |
|---|---|---|---|---|
| Checks-Effects-Interactions | Dış çağrıdan önce durum güncellemesi | Basit, etkili | Disiplin gerektirir | Temel güvenlik uygulaması |
| Reentrancy Guard (mutex) | Solidity modifier ile iç içe girişi engeller | Yineleyici çağrıları açıkça bloklar | Biraz gaz maliyeti | Tüm çekme (withdraw) fonksiyonlarında önerilir |
| Pull Payment Pattern | Kullanıcının fon çekmesini sağlar | Otomatik transfer riskini azaltır | Kullanıcı etkileşimi gerekir | Escrow ve staking kontratlarında ideal |
| Statik ve Dinamik Analiz | Otomatik ve manuel kod denetimleri | Zayıflıkları erken tespit eder | Karmaşık kontrat akışlarında kaçırabilir | Ön dağıtım güvencesi için kritik |
| Flash Loan & Delegatecall Kontrolleri | Çağıran ve işlem bağlamını doğrular | Kredi destekli reentrancy önler | Uygulaması karmaşıktır | Kredi içeren DeFi protokollerinde zorunlu |
Solidity Kod Örneği: Reentrancy Açığı Olan Kontrat ve Düzeltmesi
Zafiyetli minimal bir kontrat ve reentrancy guard ile sertleştirilmiş hali:
// Zafiyetli: bakiye güncellemeden önce çekme
contract Vulnerable {
mapping(address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) external {
require(balances[msg.sender] >= amount, "Yetersiz bakiye");
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer başarısız");
balances[msg.sender] -= amount; // Zafiyet: dış çağrıdan sonra güncellendi
}
}
OpenZeppelin ReentrancyGuard ve önce durum güncellemesi:
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract Secure is ReentrancyGuard {
mapping(address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount, "Yetersiz bakiye");
balances[msg.sender] -= amount; // Dış çağrıdan önce durum güncellendi
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer başarısız");
}
}
İpucu: Her zaman checks-effects-interactions kalıbını reentrancy koruyucularla beraber kullanın. Kontrat çağrı grafiği denetimleri ve fuzz testleri çok adımlı reentrancy zafiyetlerini dağıtımdan önce ortaya çıkarabilir.
Reentrancy zafiyetleri, özellikle flash loanlar ve delegatecall kullanılan karmaşık DeFi ekosistemlerinde kritik bir tehdit olmaya devam ediyor. En etkili savunmalar, kod disiplini (checks-effects-interactions), açık reentrancy koruyucuları, titiz denetimler ve bağlam farkında işlem doğrulamalarının birleşimidir.
Soken olarak, 255’ten fazla akıllı kontrat denetiminde elde ettiğimiz deneyimle manuel ve otomatik teknikleri harmanlayarak reentrancy ve ilişkili riskleri düzenli tespit edip gideriyoruz. Kullanıcı fonlarını yöneten her proje için en iyi uygulamalar ve derinlemesine test metodolojileri hayati önem taşır.
Uzman güvenlik rehberliğine mi ihtiyacınız var? Soken’in denetçi ekibi 255’ten fazla akıllı sözleşmeyi inceledi ve 2 milyar dolardan fazla protokol varlığını güvence altına aldı. İster bir kapsamlı denetim, ister ücretsiz bir güvenlik X-Ray değerlendirmesi ya da kripto düzenlemeleri konusunda yardım arıyor olun, size yardımcı olmaya hazırız.