Eksik giriş doğrulama saldırıları, Solidity sözleşmelerinin kullanıcı kontrollü adresleri, tutarları, kimlikleri, fiyatları veya konfigürasyon değerlerini, sözleşmenin ekonomik ve güvenlik varsayımlarını karşılayıp karşılamadığını kanıtlamadan kabul ettiği durumlarda ortaya çıkar. Bu tür saldırıları önlemek için, varlıklar hareket etmeden veya muhasebe değişiklikleri yapılmadan önce güven sınırıyla her dış girdiyi allowlistler, sınır kontrolleri, sıfır adres kontrolleri, yetkilendirme ve durum invariantsıyla doğrula.
Etki somut: Qubit, 2022-01-28 tarihinde BSC üzerinde Eksik Giriş Doğrulama olarak sınıflandırılan olayda 80.0 milyon dolar kaybetti. Bu başarısızlıklar sadece hatalı işlem sorunları değil. Kontrol edilmemiş bir değer, geçerli Solidity kodunun geçersiz bir iş modeli eylemi gerçekleştirmesine neden olabilir; örneğin, var olmayan teminatı krediye eklemek, varlıkları güvenilmeyen bir hedefe transfer etmek veya borç sınırını aşmak gibi.
Solidity’de giriş doğrulama açığı nedir ve bir saldırı nasıl işler?
Solidity’de giriş doğrulama açığı, bir sözleşmenin, çağıran tarafından sağlanan değeri güvenilir kabul ettiği durumdur; o değer, izinleri, varlık muhasebesini, fiyatlandırmayı veya durum geçişlerini kontrol ettiğinde. Bir saldırgan, sözleşmenin ABI açısından sözde geçerli, ancak protokol açısından ekonomik açıdan geçersiz olan bir değer sağlar ve ardından ortaya çıkan durumu kullanarak varlık çekebilir, talepler üretebilir veya kısıtlamaları aşabilir.
Solidity, türleri uygular, protokol niyetini değil. Bir uint256 herhangi bir hatasız sayı olabilir, bir address ise bir EOA, kötü niyetli bir sözleşme, sıfır adres veya desteklenmeyen bir token olabiliyor. Sözleşme, eksik semantik kuralları zorunlu kılmalı.
Tipik saldırı dizisi şu şekildedir:
- Saldırgan, kontrol edilmemiş bir tutar, token, alıcı, fiyat veya kimlik kabul eden genel bir fonksiyonu tanımlar.
- Saldırgan, protokolün niyet ettiği varsayımı ihlal eden bir değer seçer.
- Sözleşme, güvenli olmayan bir bakiye, hak, borç limiti veya yetkilendirme durumu kaydeder.
- Saldırgan, zehirlenmiş duruma güvenen daha sonra bir fonksiyon çağırır.
- Protokol, bu yanlış duruma dayanarak varlık transferi yapar veya devredilebilir bir talep üretir.
- Diğer kullanıcılar, muhasebe açığının görünür hale gelmesiyle kayba uğrar.
Eleştirel soru şudur: bu girişin temsil ettiği gerçek nedir ve sözleşme bu gerçeği bağımsız olarak nerede doğrular? Eğer cevap “çağıran sağladıysa” ise, sözleşmenin yanlış bir giriş doğrulama açığı vardır.
Hangi Solidity desenleri giriş doğrulama saldırılarına neden olur?
Giriş doğrulama saldırıları genellikle, bir sözleşmenin entegrasyonlar veya kullanıcı deneyimi için esneklik kabul ettiği durumlarda, bu esnekliği protokolün desteklediği alanla sınırlandırmadığı zaman ortaya çıkar. En tehlikeli parametre genellikle açıkça price veya amount olarak adlandırılmaz; bu bir token adresi, rota, alıcı, tranche kimliği, kanıt veya dış sözleşme adresi olabilir.
Yaygın güvensiz desenler şunlardır:
- Çağırandan bildirilen teminat değeri: Bir borç alan, kredi gücünü hesaplamak için kullanılan değeri sağlar.
- Rastgele token adresleri: Bir depo fonksiyonu, transfer davranışları standart olmayan herhangi bir ERC-20 kabul eder.
- Kontrol edilmemiş alıcı adresleri: Bir fonksiyon
address(0), sözleşmenin kendisi veya emanet kurallarını ihlal eden adresleri kabul eder. - Sınırsız yüzdeler ve oranlar: Bir ücret, LTV, iskonto, slippage veya ödül oranı, öngörülen temel puan aralığını aşar.
- Doğrulanmamış dizi ilişkileri: Eş zamanlı diziler uzunluk açısından farklıdır, tekrar eden girişler kabul edilir veya beklenmedik şekilde bir varlık tekrar eden rota.
- Önkoşullar olmadan durum geçişleri: Bir talep, iptal, geri ödeme veya göç eylemi yanlış yaşam döngüsü durumunda çalışır.
- Gerçekmiş gibi kabul edilen dış veri: Bir fonksiyon, çağıran tarafından sağlanan fiyatlara, bakiyelere, imzalara veya dönüş değerlerine doğrulama olmadan güvenir.
Doğrulama bağlam içinde olmalı. require(amount > 0) faydalı olsa da, bunun amount’ın karşılanabilir, teminatlı, sınır içinde veya şu anki durumla tutarlı olduğunu kanıtlamaz. Aynı şekilde, bir token adresinin sıfır olmayan olup olmadığını kontrol etmek, tokenin onaylandığını, beklendiği gibi davrandığını veya doğru piyasaya ait olduğunu göstermez.
Soken’ın inceleme metodolojisi, her dış parametreyi bir hareket durumu olarak görür: etkileyebileceği invariants’ı tespit edin ve sonra fonksiyon, bu invariant’ı yazarak değiştirmeden önce doğrular.
Solidity’de giriş doğrulama örneği nasıl görünür?
Bu giriş doğrulama saldırısı örneğinde, borç alan kendi collateralValue değerini sunabilir. Sözleşme, istenen kredinin bu değerden büyük olmadığını kontrol eder, fakat borç alanın bu tutarda teminat yatırdığını hiçbir zaman doğrulamaz. Bu nedenle, çağıran hem değeri hem de ihtiyari değeri rastgele ayarlayabilir ve borçlandırıcıdan fon elde edebilir.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
}
contract UnsafeLender {
IERC20 public immutable asset;
mapping(address => uint256) public debt;
constructor(IERC20 asset_) {
require(address(asset_) != address(0), "sıfır varlık");
asset = asset_;
}
function borrow(
uint256 collateralValue,
uint256 amount
) external {
require(collateralValue > 0, "teminat yok");
require(amount <= collateralValue, "yetersiz teminat");
// HASARLI: borç alan, krediyi destekleyen değeri sağlar.
debt[msg.sender] += amount;
require(asset.transfer(msg.sender, amount), "aktarma başarısız");
}
}
Düzeltilmiş tasarım, kredi kapasitesini gerçekten alınan teminattan türetir. Immutable varlık adresleri, dar bir allowlist görevi görür; yapıcı fonksiyon sıfır adresleri reddeder, LTV sınırlandırılmıştır ve bakiye farkı kontrolü, talep edilen depozito tutarına güvenmek yerine transferInvariant’ını doğrular.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
contract ValidatedLender {
IERC20 public immutable loanAsset;
IERC20 public immutable collateralAsset;
uint256 public immutable maxLtvBps;
mapping(address => uint256) public collateral;
mapping(address => uint256) public debt;
constructor(IERC20 loanAsset_, IERC20 collateralAsset_, uint256 maxLtvBps_) {
require(address(loanAsset_) != address(0), "sıfır kredi varlığı");
require(address(collateralAsset_) != address(0), "sıfır teminat varlığı");
require(maxLtvBps_ > 0 && maxLtvBps_ <= 10_000, "geçersiz LTV");
loanAsset = loanAsset_;
collateralAsset = collateralAsset_;
maxLtvBps = maxLtvBps_;
}
function depositCollateral(uint256 amount) external {
require(amount > 0, "sıfır tutar");
uint256 beforeBalance = collateralAsset.balanceOf(address(this));
require(collateralAsset.transferFrom(msg.sender, address(this), amount), "aktarım başarısız");
uint256 received = collateralAsset.balanceOf(address(this)) - beforeBalance;
// DÜZELTME: sadece gerçekten alınan teminatı dikkate al.
require(received == amount, "desteklenmeyen token davranışı");
collateral[msg.sender] += received;
}
function borrow(uint256 amount) external {
require(amount > 0, "sıfır tutar");
uint256 limit = (collateral[msg.sender] * maxLtvBps) / 10_000;
require(debt[msg.sender] + amount <= limit, "kredi sınırı aşıldı");
debt[msg.sender] += amount;
require(loanAsset.transfer(msg.sender, amount), "aktarma başarısız");
}
}
Eğer protokolünüz esnek varlıklar, rotalar veya muhasebe girdileri kabul ediyorsa, saldırgan akıllı sözleşme incelemesi ve penetrasyon testi hizmeti her bir iddia edilen değerin fonlara etki etmeden önce bağımsız olarak belirlendiğini izleyebilir.
Solidity’de giriş doğrulama saldırılarını nasıl önlersiniz?
Giriş doğrulama saldırılarını önlemek, girdileri girişte doğrulamayı ve sözleşme yaşam döngüsü boyunca bu varsayımları açık invariants ile korumayı gerektirir. En iyi savunma tek bir modifier değil; anlamlı her durum değişikliğinin açıkça tanımlanmış izin verilen girişler ve sonra doğrulanabilir bir durumu kalan tasarımdır.
| Teknik | Ne durdurur | Gas veya karmaşıklık maliyeti | Sınırlama |
|---|---|---|---|
| Token ve uygulama allowlistleri | Desteklenmeyen ERC-20’ler, kötü niyetli adaptörler, rastgele harici çağrılar | Depolama arama veya immutable adres karşılaştırması | Onaylanan tokenler ekonomik riski yine de getirebilir |
| Sınır kontrolleri | Sıfır tutarlar, aşırı oranlar, geçersiz temel puanlar, güvensiz son teslim süreleri | Düşük, genellikle birkaç karşılaştırma | Sınırlar tek başına ekonomik doğruluk sağlamaz |
| Sıfır adres ve alıcı kontrolleri | Varlık yakma, kullanılamaz sahiplik, geçersiz emanet hedefleri | Düşük, bir adres karşılaştırması | Sıfır olmayan adres yine güvenilmez olabilir |
| Yetkilendirme ve yaşam döngüsü kontrolleri | Yanlış durumda veya yanlış aktör tarafından çağrı | Depolama okuma ve rol tasarımı | Roller güvenli yönetim gerektirir |
| Bakiye farkı doğrulaması | Yanlış depo kredi ve desteklenmeyen token transfer davranışı | Ek token bakiyesi okuma | Rebase varlıkların dikkatli yönetimini gerektirir |
| Invariant doğrulaması | Bozuk ödeme kabiliyeti, arz, borç ve rezerv ilişkileri | Ek okuma ve aritmetik | Invariants, tüm ekonomik modeli kapsamalıdır |
Yapılandırılabilir protokoller için, yapılandırmayı hem oluştururken hem de kullandığında doğrula. Bir yönetişim tarafından belirlenen parametre, oluşturulduğunda güvenli olabilir; ancak bir bağımlılık değişince güvensiz hale gelir. Yeniden kullanılabilir sistemlerde, başlatıcı parametreleri, genel fonksiyon girişleri kadar titizlikle doğrula.
Güvenlik içgörüsü: Soken metodolojisi, invariant’ten başlar,
requireifadesinden değil. İncelerler, bir kullanıcı kontrollü giriş işlendiğinde neyin doğru kalması gerektiğini söyleyemiyorsa, doğrulamanın yeterli olup olmadığını belirleyemezler.
Eksik giriş doğrulama olarak sınıflandırılan gerçek olaylar nelerdir?
Eksik giriş doğrulama, borç verme, takas ve varlık yönetimi kontekstinde maddi akıllı sözleşme kayıplarıyla ilişkilendirilmiştir. Bu olay kategorisi, farklı zincirler ve protokol tasarımlarıyla genişler; yanlış giriş doğrulamasının bir protokol- mantık hatası olduğu ve ağ spesifik Solidity hatası olmadığı gösterir.
| Protokol | Tarih | Kaybedilen tutar | Zincir |
|---|---|---|---|
| Qubit | 2022-01-28 | 80.0 Milyon ABD Doları | BSC |
| Hedgey | 2024-04-19 | 44.7 Milyon ABD Doları | Arbitrum, Ethereum |
| Transit Swap | 2022-10-02 | 28.9 Milyon ABD Doları | Ethereum, BSC |
| Pickle | 2020-11-22 | 19.7 Milyon ABD Doları | Ethereum |
Bu olayların ortak dersi: sözleşmeler, sadece bir işlem bu değeri kodlayıp geçtikten sonra protokol gerçekliğini güvenli şekilde çıkaramaz. Varlık sistemleri, teminat alınan değer, desteklenen varlık, yetkilendirilmiş rota veya geçerli yaşam döngüsü geçişi gibi, değeri koruyan belirli özellikler around semantik doğrulama gerektirir.
DeFiLlama, 2020’den 2026’ya kadar 52 akıllı sözleşme olayını Eksik Giriş Doğrulama altında sınıflandırır ve toplamda 330.5 milyon dolar kayıp bildirmiştir. Bu genişlik, Soken’ın doğrulama incelemesini yüzeysel require ifadeleri listesi değil, ekonomik ve güvenlik odaklı bir değerlendirme olarak görmesine neden olur.
Eksik giriş doğrulama açıklarını nasıl tespit edebilirsiniz?
Eksik giriş doğrulama açıklarını, her dış erişilebilir parametrenin, etkileşime geçtiği depolama yazma, dış çağrı ve varlık transferleriyle izleyerek tespit edebilirsiniz. Sonra, geçersiz ama ABI açısından geçerli değerlerin, invariant’ı ihlal edip etmediğini sınar. Statik analiz bazı eksik kontrolleri bulabilir, ancak protokol spesifik varsayımların doğrulanması için senaryo tabanlı testler gereklidir.
Bu inceleme kontrol listesini kullanın:
- Değeri, otoriteyi veya yönlendirmeyi etkileyen her
externalvepublicfonksiyon parametresini listeleyin. - Her adresin sıfır olmayan, onaylanmış ve rolüne uygun olup olmadığını belirleyin.
- Her tutarı protokol sınırları, bakiye, borç limiti, arz sınırları ve ondalık varsayımlarıyla kontrol edin.
- Fiyatların, teminat değerlerinin ve bakiyelerin güvenilir ya da bağımsız olarak doğrulanmış kaynaklardan geldiğinden emin olun.
- Dizilerin uzunluklarını, benzersizliğini, sıralamasını ve çapraz dizi indeks ilişkilerini doğrulayın.
- Her fonksiyonun sadece geçerli yaşam döngüsü durumlarına ve yetkili çağıranlara izin verdiğinden emin olun.
- Ücret, rebase ve özel ERC-20 davranışları gibi bakiye farkı muhasebesini test edin.
- Her varlık hareketinin sonrası durumu ve durumu sınayın.
Slither, tehlikeli harici çağrılar, kontrol edilmemiş dönüş değerleri ve zayıf erişim kontrolleri gibi desenleri tespit edebilir; ancak her protokol invariant’ini çıkaramaz, bu nedenle Foundry fuzzing ile sıfır, maksimum değerler, çift diziler, beklenmedik adresler ve desteklenmeyen tokenlar oluşturun.
Invariant testleri özellikle etkilidir. Örneğin, toplam dış borcun, yapılandırılmış kredi kapasitesini aşmadığını, kredilendirilen teminatın alınan varlıkları geçtiğini ve yalnızca onaylanan varlıkların bir piyasa muhasebesini değiştirebildiğini test edin. Bu özellikler etrafında geniş bir güvenlik inceleme süreci kurarken Soken Hub’ı keşfedin.
Giriş doğrulama, kullanıcı niyeti ile protokol gerçekliği arasındaki sınırdır. Bir sözleşme, sadece çağıranın iddiasına dayanarak kredi, yetkilendirme, fiyatlandırma veya transfer yapmamalıdır. Duyarlı değerleri doğrulanmış durumlardan türetin, kabul edilen alanları sınırlandırın ve sonucu ekonomik olarak güvenli hale getiren invariant’ı zorunlu kılın.
Pratik adım, kod tabanınızdaki her varlık hareket fonksiyonu için parametre-invariant haritası oluşturmaktır. Belgelenmiş güven kaynağı, izin verilen aralık ve sonrası durum olmadan herhangi bir parametre hemen inceleme gerektirir.