Akıllı sözleşmeler, bir blockchain ağındaki adres üzerinde bulunan kod ve kalıcı durumdan oluşur. Kullanıcı veya başka bir sözleşme işlem gönderdiğinde ağdaki düğümler aynı girdiyi aynı kurallarla çalıştırır ve ortaya çıkan durum değişikliğinde uzlaşır.
Akıllı sözleşme gerçekte nedir?
“Sözleşme” kelimesi hukuki bir metin izlenimi verse de teknik açıdan smart contract, belirli fonksiyonları ve verileri barındıran programdır. Örneğin bir sözleşme bakiyeleri, yetki rollerini veya bir teklifin durumunu saklayabilir; transfer, oy verme ya da kayıt güncelleme gibi fonksiyonlar sunabilir. Kodun izin verdiği koşullar sağlanmıyorsa işlem başarısız olur ve durum değişikliği uygulanmaz.
Ethereum benzeri hesap tabanlı ağlarda iki temel hesap türü bulunur. Harici sahipli hesaplar özel anahtarla kontrol edilir; sözleşme hesapları ise kendi koduna göre hareket eder. Bir cüzdan, hesabın kendisi değil, anahtarları ve işlemleri yönetmek için kullanılan arayüzdür. Bu ayrımı bilmek yetki modelini doğru tasarlamak açısından önemlidir.
Kod, durum ve adres
Sözleşme dağıtıldığında derlenmiş kod belirli bir adrese yerleşir. Durum değişkenleri ağın ortak durumunda tutulur. Her fonksiyon herkese açık olmak zorunda değildir: görünürlük ve erişim kontrolleri, hangi çağrının kim tarafından yapılabileceğini belirler. Fakat arayüzde gizlenen bir buton güvenlik sağlamaz; yetki mutlaka sözleşme kodunda denetlenmelidir.
Blockchain verisi genel olarak şeffaftır. Kaynak kodu yayımlanmasa bile bytecode ve depolama ağ üzerinde görülebilir. Bu nedenle zincire parola, kişisel bilgi veya ticari sır yazmak doğru değildir. “Private” değişkeni, Solidity bağlamında diğer sözleşmelerin doğrudan erişimini sınırlar; veriyi gözlemcilerden şifrelemez.
Akıllı sözleşmenin güvenliği yalnızca kodun hatasız olmasına değil; yetki, yükseltme, oracle, kullanıcı arayüzü ve operasyon süreçlerinin birlikte tasarlanmasına bağlıdır.
Derlemeden kesinleşmeye yaşam döngüsü
Geliştirici Solidity gibi yüksek seviyeli bir dilde kod yazar. Derleyici bu kodu sanal makinenin çalıştıracağı bytecode’a ve uygulamaların sözleşmeyle nasıl konuşacağını tarif eden ABI’ye dönüştürür. Dağıtım işlemi ağa gönderildiğinde yeni adres oluşturulur; bytecode ve ilk durum zincire kaydedilir. Dağıtım da hesaplama ve depolama tükettiği için ücretlidir.
ABI, fonksiyon adlarını, parametre türlerini ve dönüş değerlerini tanımlar. Web veya mobil uygulama kullanıcı girdisini ABI’ye göre kodlar ve çağrı verisine dönüştürür. Kullanıcı imzalamadan önce hedef ağ, sözleşme adresi, çağrılan fonksiyon, gönderilen değer ve olası ücret açıkça gösterilmelidir. Arayüzün ürettiği her işlem, kullanıcının cüzdanında ayrıca doğrulanabilir olmalıdır.
Okuma ve yazma çağrıları
Durumu değiştirmeyen okuma çağrıları yerel bir düğüm üzerinde simüle edilebilir; ağın ortak durumuna kayıt bırakmadığı için genellikle kullanıcı işlemi ve gas ödemesi gerektirmez. Durumu değiştiren yazma çağrıları ise imzalı işlem olarak yayınlanır, doğrulayıcı tarafından bloğa alınır ve ağdaki düğümlerce yeniden yürütülür.
İşlemin başarılı görünmesi her zaman iş hedefinin gerçekleştiği anlamına gelmez. Uygulama, işlem makbuzunu ve sözleşmenin ürettiği olayları izlemeli; yeniden yapılanma veya gecikmiş kesinlik gibi ağ koşullarını hesaba katmalıdır. Kullanıcıya “gönderildi”, “onaylandı” ve “kesinleşti” durumlarını ayrı göstermek daha doğru bir deneyim sağlar.
Deterministik yürütme, gas ve dış dünya
Ağdaki her düğüm aynı işlemi yürüttüğü için sonuç deterministik olmalıdır. Sözleşme doğrudan rastgele bir web API’sine istek atamaz; düğümler farklı yanıt veya zamanlama görebilir. Zincir dışı fiyat, hava durumu ya da maç sonucu gibi veriler oracle mekanizmalarıyla zincire taşınır. Oracle bu noktada veri kaynağı, güncellik, bütünlük ve kesinti riskini sisteme dahil eder.
Gas, işlemin tüketebileceği hesaplama kaynaklarını ölçer ve sonsuz döngü gibi kötüye kullanım senaryolarını sınırlar. Depolamaya yazmak, hesaplama yapmak ve başka sözleşme çağırmak farklı maliyetlere sahiptir. Kullanıcı gas sınırını belirler; yürütme bu sınırı aşarsa işlem geri alınır, ancak doğrulayıcıların harcadığı kaynak nedeniyle ücretin bir bölümü yine tüketilir.
Oracle ve köprü riski
Bir protokol doğru çalışan kodla kurulmuş olsa bile yanlış veya gecikmiş oracle verisi zarara yol açabilir. Tek bir veri sağlayıcısına bağımlılık, düşük likiditeli piyasalardan kolayca manipüle edilen fiyat almak ve kesinti anında güvenli moda geçememek kritik risklerdir. Kaynak çeşitliliği, zaman ağırlıklı ölçümler, güncellik sınırları ve devre kesiciler bu riski azaltabilir.
Farklı ağlar arasındaki köprüler de ek bir güven alanı oluşturur. Mesajın diğer zincirde gerçekten kesinleştiği nasıl kanıtlanıyor? İmzacı grubu kaç kişiden oluşuyor? Sözleşmeler yükseltilebiliyor mu? Köprüde tutulan değer arttıkça bu soruların önemi de artar.
En kritik güvenlik alanları
Akıllı sözleşmeler varsayılan olarak geri döndürülemez ve herkese açık bir ortamda çalışır. Hata bulunduktan sonra yama yayınlamak geleneksel web uygulamasındaki kadar kolay olmayabilir. Bu yüzden tasarımın ilk gününden tehdit modeli çıkarmak gerekir: korunacak varlık nedir, kim hangi yetkiye sahiptir, saldırgan hangi dış sistemi etkileyebilir ve başarısızlık anında sistem nasıl durdurulur?
Erişim kontrolü ve yönetici anahtarları
Yanlış erişim kontrolü, kritik fonksiyonların yetkisiz çağrılmasına yol açar. Yalnızca sözleşme sahibine açık fonksiyonlar açık biçimde tanımlanmalı; sahiplik devri iki aşamalı olmalı ve gereksiz ayrıcalıklar kaldırılmalıdır. Tek bir yönetici anahtarı, tüm protokol için tek hata noktası yaratır. Çoklu imza, zaman kilidi ve rol ayrımı yönetim riskini azaltabilir; ancak bu yapıların kimlerden oluştuğu da şeffaf olmalıdır.
Dış çağrılar ve yeniden giriş
Bir sözleşme başka bir sözleşmeye çağrı yaptığında kontrol geçici olarak dış koda geçer. İç durum güncellenmeden önce dış çağrı yapılırsa karşı taraf aynı fonksiyona yeniden girerek beklenmeyen davranış üretebilir. Durum kontrollerini önce yapmak, etkileri kaydetmek ve dış etkileşimi sona bırakmak; yeniden giriş korumalarıyla birlikte yaygın savunma yaklaşımıdır.
Yükseltilebilirlik ödünleşimi
Değiştirilemez kod yönetişim riskini azaltırken bulunan bir hatayı düzeltmeyi zorlaştırır. Proxy tabanlı yükseltilebilir yapı hatalara müdahale olanağı sunar fakat yönetici yetkisi, depolama uyumluluğu ve kullanıcıların hangi koda güvendiği konusunda yeni riskler yaratır. Yükseltme yetkisi, bekleme süresi ve geri alma planı dokümante edilmelidir.
Güvenli geliştirme için yaşam döngüsü
- Varlıkları, aktörleri ve güven sınırlarını içeren tehdit modeli oluşturun.
- Yetkileri en az ayrıcalık ilkesiyle tasarlayın; yönetici işlevlerini sınırlayın.
- Birim, entegrasyon, özellik tabanlı ve değişmezlik testlerini birlikte kullanın.
- Bilinen saldırı sınıfları için statik analiz ve fuzz testleri çalıştırın.
- Bağımsız güvenlik incelemesi yaptırın; denetimi garanti belgesi olarak görmeyin.
- Dağıtımdan sonra olayları izleyin, eşikler ve acil durum prosedürleri tanımlayın.
- Sözleşme adreslerini, derleyici ayarlarını ve yönetim rollerini doğrulanabilir biçimde yayımlayın.
Denetim raporu belirli bir sürümün, belirli kapsam ve süre içinde incelendiğini gösterir. Sonradan yapılan yükseltme, farklı dağıtım parametreleri veya oracle değişikliği raporun kapsamadığı riskler doğurabilir. Güvenlik tek seferlik onay değil, geliştirme ve işletme boyunca devam eden süreçtir.
Kullanıcı tarafında da temel kontroller önemlidir: doğru ağda bulunmak, sözleşme adresini güvenilir kaynaktan doğrulamak, sınırsız harcama izinlerinden kaçınmak ve imzalanan çağrının ne yaptığını anlamak gerekir. İyi tasarlanmış bir protokol bu kontrolleri anlaşılır hâle getirir; hatayı yalnızca kullanıcıya yüklemez.
Kaynak notları
Kavramlar için Ethereum akıllı sözleşme belgeleri, hesap ve işlem modeli için Ethereum hesapları ile işlem belgeleri, güvenli geliştirme ilkeleri için Solidity güvenlik değerlendirmeleri kullanılmıştır.