Solidity'de Bozuk Erişim Kontrol Saldırılarını Nasıl Önlenir?

Makale yazarı

Kırık erişim kontrolü saldırıları, bir Solidity sözleşmesinin, asset hareketleri, uygulama değiştirme, roller atama veya güvenilir adres yapılandırması gibi sınırlandırılması gereken durumlara erişimi olan güvenilmeyen bir çağrıcıya izin verdiği durumlarda gerçekleşir. Saldırganın kriptografiyi kırmasına gerek yoktur: eksik, yanlış veya çok geniş yetkilendirme kontrolünü istismar ederek etkin ayrıcalık yükseltmesi sağlar.

Bu durum, genellikle ayrıcalıklı fonksiyonların havuz fonlarını veya yönetişimle kritik yapılandırmayı kontrol ettiği protokol çapında etki yaratabilir. Poly Network, 2021-08-10 tarihinde Ethereum, BSC ve Polygon üzerinde toplam 611.0M$ kaybetmiş ve bu olay, DefiLlama tarafından Yanlış Erişim Kontrolü olarak sınıflandırılmıştır. Yetkilendirme, bu nedenle bir UI veya yönetim detayından çok, sözleşmenin temel güvenlik sınırlarının bir parçasıdır.

Solidity’de Kırık Erişim Kontrolü Güvenliği Açığı Nedir?

Kırık erişim kontrolü açığı, bir sözleşmenin msg.sender’ın yetkili olup olmadığını güvenilir şekilde doğrulamaması veya yetkilendirme modelinin, o işlemin gerektirdiğinden daha fazla yetki vermesi durumunda oluşur. Solidity’de, bu genellikle hassas depolamayı değiştiren, varlık transferi yapan, kodu yükselten veya güvenilir tarafları değiştiren harici çağrılabilir fonksiyonlarda görünür.

Bir sözleşme, owner değişkenine sahip olsa bile savunmasız olabilir. Kritik olan, her yetkili yürütme yolunun, yardımcı fonksiyonlar, başlatıcılar, rol yönetimi fonksiyonları ve yükseltme kancaları dahil olmak üzere, yetkiyi doğru şekilde kontrol edip etmediğidir.

Tipik bir kırık erişim kontrolü saldırısı aşağıdaki şekilde ilerler:

  1. Saldırgan, yetkili sonuçlar doğuran bir harici çağrılabilir fonksiyon tespit eder.
  2. Bu fonksiyon, çağırıcı kontrolü yapmaz, yanlış adresi kontrol eder veya saldırganın kontrolünde olan durumda bağlıdır.
  3. Saldırgan, herhangi bir ön yüz kısıtlamasını aşarak doğrudan fonksiyonu çağırır.
  4. Çağrı, bir rol atar, güvenilir adresi değiştirir veya asset hareketi yapan bir işlemi tetikler.
  5. Saldırgan, yeni kazandığı yetkiyle fonları çeker veya protokol davranışını değiştirir.
  6. Sözleşme, EVM’de yalnızca zincir içi kontrollerin zorunlu tutulması nedeniyle işlemi kabul eder.

Ön yüz düğmeleri, dokümantasyon ve operasyonel prosedürler doğrudan sözleşme çağrılarını engellemez. Herhangi bir hesap, açık veya harici fonksiyona calldata gönderebilir. Bu nedenle, Solidity kodunun, hassas durum geçişinin gerçekleştiği noktada, uygun politikayı zorunlu kılması gerekir.

Hangi Solidity desenleri erişim kontrolü saldırıları ve ayrıcalık yükseltmelerine neden olur?

Yanlış erişim kontrolü açıkları, genellikle geliştiricilerin yapılandırma ayarlarını, yönetici yardımcılarını veya başlatma yollarını açığa çıkardığında ortaya çıkar — ki bu, her kamu fonksiyonunun bir saldırganlarla temas eden API olduğu gerçeğini göz önünde bulundurmak zorundadır. Bu tehlikeli desen, yalnızca eksik onlyOwner modifikatörü ile sınırlı değildir: yetkilendirme, herhangi bir çağırıcı tarafından değiştirilebilir, yanlışlıkla miras alınmış, tutarsız şekilde uygulanmış veya operasyon için çok geniş olabilir.

Yaygın başarısızlık desenleri şunlardır:

  • Herkese açık ayarlayıcılar, herhangi biri tarafından değiştirilebilir şekilde tasarlanmış.
  • Yeterli yönetici kontrolüne sahip olmayan rol yönetim fonksiyonları.
  • Dağıtım sonrası çağrılabilen veya beklenmedik bir hesap tarafından erişilebilen başlatıcılar.
  • tx.origin yerine msg.sender kontrolü yapılması.
  • Korumasız bir dış sarmal aracılığıyla ulaşılabilen yetkili iç fonksiyon.
  • Tüm operasyonel işlemleri gerçekleştirebilecek tek bir yönetici rolü, saldırı alanını genişletir.
  • Sabit veya kontrol edilen rol eşleştirmeleri yerine, kullanıcının sağladığı adreslere dayalı yetkilendirme.
  • Çağıranın doğrulandığı, yeni uygulamanın veya yükseltme yolunun doğrulanmadığı yükseltme fonksiyonları.

Bu hatalı desen, özellikle sinsi ve zor fark edilen bir örnektir:

function setOperator(address newOperator) external {
    operator = newOperator;
}

Ödeme fonksiyonu, doğru şekilde msg.sender == operator gereksinimi getiriyor olabilir, fakat erişim sınırı zaten başarısız olmuştur çünkü herkes kendisini operatör olarak atayabilir. İnceleyenler, her hassas fonksiyondan geriye doğru izleyerek, bu fonksiyonun hangi rolü alabileceğini bulmalıdır.

Soken metodolojisi, rol atamasını ve güvenilir adres yapılandırmasını, kendi başlarına yetkili işlemler olarak kabul eder. Güvenli bir erişim kontrol tasarımı, hem son asset transferini hem de onu açabilecek her yolu korur.

Kırık erişim kontrolü saldırısı Solidity kodunda nasıl görünür?

Bu savunmasız vault, ödeme öncesinde çağırıcıyı kontrol eder, ancak setPayoutOperator fonksiyonu açıktır. Bir saldırgan, kendisini operatör olarak atayabilir ve sonra pay fonksiyonunu çağırabilir, böylece son yetkilendirme kontrolünü anlamsız hale getirir.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract VulnerablePayoutVault {
    address public payoutOperator;

    constructor(address initialOperator) {
        payoutOperator = initialOperator;
    }

    receive() external payable {}

    function setPayoutOperator(address newOperator) external {
        // ZAYIF: herhangi biri kendisini payout yetkisi ile atanabilir.
        payoutOperator = newOperator;
    }

    function pay(address payable recipient, uint256 amount) external {
        require(msg.sender == payoutOperator, "not operator");
        require(address(this).balance >= amount, "insufficient balance");

        (bool sent, ) = recipient.call{value: amount}("");
        require(sent, "payment failed");
    }
}

Çözüm, yönetim ve operasyonların ayrılmasıdır. Sadece sahibi, belirli sınırlar içindeki ödeme rolünü verir veya iptal eder; ödeme operatörü rol ve sahipliği yönetemez.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract FixedPayoutVault {
    address public owner;
    mapping(address => bool) public payoutOperators;

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    modifier onlyPayoutOperator() {
        require(payoutOperators[msg.sender], "not payout operator");
        _;
    }

    constructor(address initialOwner, address initialOperator) {
        require(initialOwner != address(0), "zero owner");
        require(initialOperator != address(0), "zero operator");
        owner = initialOwner;
        payoutOperators[initialOperator] = true;
    }

    receive() external payable {}

    function setPayoutOperator(address operator, bool allowed) external onlyOwner {
        require(operator != address(0), "zero operator");
        // DÜZELTME: sadece sahibi, ayrıcalıklı rol üyeliğini değiştirebilir.
        payoutOperators[operator] = allowed;
    }

    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "zero owner");
        owner = newOwner;
    }

    function pay(address payable recipient, uint256 amount)
        external
        onlyPayoutOperator
    {
        require(address(this).balance >= amount, "insufficient balance");
        (bool sent, ) = recipient.call{value: amount}("");
        require(sent, "payment failed");
    }
}

Eğer sisteminizde rol değişiklikleri, yükseltmeler veya tutar çekimleri varsa, erişim-denetimi odaklı akıllı sözleşme denetimi ve güvenlik değerlendirmesi, bu yeteneklere ulaşan tüm yolların uygun şekilde sınırlandırıldığını izleyebilir.

Solidity geliştiricileri yanlış erişim kontrolü güvenlik açıklarını nasıl önleyebilir?

Kırık erişim kontrolü saldırılarını önlemek, tamamlanmış bir fonksiyonellik sonrası rastgele require ifadeleri eklemek yerine, açık bir izin modeli gerektirir. Hangi aktörün, hangi hassas işlemi gerçekleştirebileceğini, o yetkinin neden var olduğunu ve hangi küçük rolün güvenli şekilde rutin görevleri yapabileceğini tanımlayın.

Teknik Ne idiğini engeller Gas veya karmaşıklık maliyeti Sınırlaması
onlyOwner modifikasyonu Yüklenici dışı fonksiyonların yetkisiz yönetimi Korunan çağrı başına bir depolama okuma Bir kompromize olmuş sahibi, tam yetki sağlar
Rol eşlemeleri veya OpenZeppelin AccessControl Farklı operasyonel rollerin yetkisiz kullanımı Depolama okuma ve rol yönetimi mantığı Kötü rol tasarımı hala aşırı ayrıcalıklar yaratabilir
En az ayrıcalık ilkeleri Bir bakıcı veya operatörün ilgisiz yönetim güçleri kullanması Daha fazla fonksiyon ve rol tanımı Açık operasyonel sınırlar gerektirir
Kritik değişiklikler için zaman kilitleri Anında kötü niyetli yükseltmeler veya parametre değişiklikleri Gecikmeli yürütme ve ek sözleşmeler Kullanıcılar tepki veremiyorsa, gecikme sonrası kötü niyetli hareketleri önlemez
Çok imzalı yönetim Tek bir anahtarın, ayrıcalıklı durumu tek taraflı değiştirmesi İmza sahibleri koordinasyonu ve operasyonel yük Paylaşımlı imzalayanlar veya zayıf politikalar risk oluşturur
Tek seferlik başlatma korumaları Yetkisiz veya tekrar eden başlatma Bir depolama bayrağı ve başlatıcı mantığı Dağıtım prosedürleri, hedef yetkiyi yine de ayarlamalıdır

İyi incelenmiş sahiplik ve rol ilkeleri kullanın; ancak, bir kütüphane, tam bir güvenlik modeli değildir. Örneğin, OpenZeppelin Ownable, sahiplik mekaniklerini sağlar, fakat protokol ekibi, sahipliğin duraklatma, yükseltme, ücret toplama, oracle değiştirme ve acil durum kurtarma gibi fonksiyonlara kontrol edip etmeyeceğine karar vermelidir.

tx.origin kullanımdan kaçının. Aracı sözleşmeler yoluyla etkilenebilir ve doğrudan çağıranı tanımlamaz. Bunun yerine, msg.sender kullanın ve ardından onu tanımlanmış bir sahibi, rolü, multisig veya sözleşmeye özel yetki kurallarına göre doğrulayın.

Erişim kontrolü saldırılarının etkisini göstermek için gerçek olaylar nelerdir?

DefiLlama, 2020’den 2026’ya kadar, borsa ve cüzdan ihlalleri hariç olmak üzere, toplam 130 yanlış erişim kontrolü sınıflandırmasına sahip akıllı sözleşme olayını kaydetmiştir ve toplam kayıplar 909.7M$’a ulaşmaktadır. Aşağıdaki doğrulanmış olaylar, erişim-denetimi hatalarının köprüleri, DeFi protokolleri, botlar ve uygulamaları çoklu zincirler üzerinde etkilediğini göstermektedir.

Protokol Tarih Tutar Zincir
Poly Network 2021-08-10 611.0M$ Ethereum, BSC, Polygon
Mirror 2021-10-08 90.0M$ Terra
Wintermute 2022-06-05 17.6M$ Optimism
ValueDefi 2021-05-05 10.0M$ BSC
Cork V1 2025-05-28 12.0M$ Ethereum
SUPERFORTUNE AI 2026-05-27 15.2M$ Ethereum
The Sandbox 2026-08-22 675K$ Base, BSC, Ethereum
Radix 2026-08-31 1.2M$ Radix

Bu olaylar, protokolün ekonomik değerinin, bir sözleşmenin yetki sınırının, tasarımındaki güvenilirlik modeliyle uyuşmaması halinde açığa çıkabileceği ortak bir güvenlik dersidir. Etkilenmiş fonksiyonlar farklı olabilir; ancak başarısızlık sınıfı aynıdır: bir aktör, tasarımın elinde tutması gereken yetkiye ulaşır veya onu kullanır.

Deploy edilmeden önce kırık erişim kontrolü açıklarını nasıl tespit edebilirsiniz?

Erişim kontrolü açıklarını tespit etmek, hassas durum değişikliklerini yetkilendirme koşullarına eşleştirmeyi ve bu koşullardan herhangi birini atlamanın mümkün olmadığını göstermeyi gerektirir. Otomatik araçlar şüpheli desenleri tanımlamaya yardımcı olsa da, iş yetkisi, güven varsayımları ve ayrıcalık yükseltme zincirlerini anlamak için insan incelemesi zorunludur.

Bu inceleme kontrol listesi yardımcı olabilir:

  1. Asset transferi, rol değişikliği, kod yükseltme, duraklatma veya güvenilir adres değiştiren her fonksiyonu listeleyin.
  2. Her listedeki fonksiyonun amaçlanan çağırıcı ve yetkilendirme kurallarını belirleyin.
  3. Bu yetkiye erişimi sağlayan, kaldıran, transfer eden veya başlatan fonksiyonları izleyin.
  4. Yetkili iç fonksiyonlara ulaşan tüm harici sarıcıları kontrol edin.
  5. Başlatıcının yalnızca bir kez çalıştırılabildiğinden ve yalnızca hedef dağıtım sürecinde olacağından emin olun.
  6. Acil durum rolleri ile ilgisiz rutin veya yönetişim işlemlerinin yapılmadığını teyit edin.
  7. Rol iptali, sahiplik transferi ve sıfır-adres işlemlerini test edin.
  8. Proxy’leri, miras alınmış sözleşmeleri ve delegatecall yollarını aynı yetki sınırı kapsamında inceleyin.

Slither, eksik yetkilendirme desenlerini, tehlikeli tx.origin kullanımını ve tutarsız modifikatorleri bayraklayabilir; ancak bulguların manuel doğrulaması gerekir. Foundry fuzzing, rastgele adreslerden çağrı üretmek ve yetkisiz çağırıcıların yetkili durumu değiştirmesini engellemek için faydalıdır.

Özdeğer testleri özellikle etkilidir. Örneğin, bir vault’taki bir değişiklik, payout rolü olmayan bir adresin, pay üzerinden vault bakiyesini azaltmasına neden olmamalıdır. Bir başka özdeğer, yalnızca sahibi tarafından rol üyeliğinin değiştirilmesini sağlar. Bu özellikler, yalnızca beklenen kullanıcı akışlarını değil, doğrudan güvenlik kurumunu test eder.

Güvenlik içgüdüsü, Soken metodolojisi: Yetkilendirmeyi, modifikatör listesi yerine, bir yetki kapasiteleri grafiği olarak inceleyin. Her yetkili sonucu, kasıtlı ve denetlenebilir bir yola sahip olmalı ve her istenmeyen yol, potansiyel bir yükseltme rotasıdır.

Kırık erişim kontrolü saldırıları, yetki açıklarını belirgin hale getirerek, her rolün yetkilerini en aza indirerek ve bu yetkileri atayan fonksiyonları, fonlar hareket ederkenki fonksiyonlar kadar titizlikle koruyarak önlenir. Doğru kısıtlanmış bir çekim fonksiyonu, sadece biri atanabiliyorsa güvenli değildir.

Dağıtılmış ve planlanan sözleşmeleriniz, proxyleri ve operasyonel hesapları içeren bir yetki haritası oluşturarak başlayın ve her kuralı modifikator ve yükleme testi haline getirin. Daha derin Solidity güvenlik araştırmaları ve bağlantılı açık sınıflar için Soken Hub sayfasını keşfedin.

Makale yazarı

Sıkça Sorulan Sorular

Solidity'de bozuk erişim kontrolü zafiyetleri nedir?

Solidity'de bozuk erişim kontrolü, bir kontratın msg.sender'ın yetkili olduğunu güvenilir şekilde doğrulamaması durumudur. Bu, güvenilmeyen çağrıların state-changing yetkilerine ulaşmasına yol açar, böylece kriptografi bozulmadan privilege escalation mümkün olur.

Bozuk erişim kontrol saldırıları privilege escalation'ı nasıl sağlar?

Solidity kontratları, yetkisiz bir çağrıcının yalnızca yetkili olduğu kapasiteleri kullanmasına izin verirse, privilege escalation oluşur. Çağrıcı, varlık hareketi veya rol atama gibi state-changing işlemler yapabilir.

Hangi Solidity işlemleri erişim kontrolü ile sınırlandırılmalı?

Varlık transferleri, kontrat güncellemeleri, rol atamaları ve güvenilir adres yapılandırması gibi, yetkisiz çağrıcılara açık olmayan tüm state-changing işlemler erişim kontrolü ile sınırlandırılmalı. Her biri güvenilir yetkilendirme gerektirir.

Poly Network erişim kontrol olayı neydi?

2021-08-10'da Poly Network, Ethereum, BSC ve Polygon üzerinden toplam 611 milyon dolar kaybetti. Bu olay, yetkilendirme kontrollerinin yalnızca yönetim değil, pooled fonlar ve yönetişim ayarları için de önemli olduğunu gösteriyor.

Neden yetkilendirme Solidity'de temel bir güvenlik sınırıdır?

Yetkilendirme, pooled fonlar ve yönetişim ayarlarını kontrol eden yetkili fonksiyonlar nedeniyle temel güvenlikdir. Eksik veya yanlış yetkilendirme, güvenilmeyen çağrıların yetki almasını sağlar, böylece güvenlik riskleri oluşur.

Sohbet