Kami baru saja melihat bagaimana celah kecil menyebabkan kerugian finansial (dengan besarnya bervariasi), dengan cara yang sama kontrak pintar yang dikembangkan di atas Solidity rentan terhadap berbagai serangan yang diketahui dan tidak diketahui. Para pengeksploitasi memanfaatkan bug, dan celah untuk mengintip kontrak pintar dan memanipulasinya untuk melakukan serangan. Di sini kami menyajikan daftar lengkap dari 5 kesalahan teratas yang sering ditemui dalam bahasa pemrograman Solidity.
Di QuillAudits, kami mengikuti metodologi adaptif untuk mendapatkan inti dari setiap peretasan dan menerapkan pembelajarannya pada kontrak pintar di masa mendatang untuk menghindari potensi ancaman.
Kesalahan dalam bahasa pemrograman soliditas
1. Panggilan Eksternal Tidak Dicentang
Kami menarik masalah ini sejak awal karena ini adalah salah satu perangkap Soliditas yang paling sering diamati. Umumnya, untuk mengirim eter ke akun eksternal apa pun dilakukan melalui transfer() fungsi. Selain itu, dua fungsi yang paling banyak digunakan untuk melakukan panggilan eksternal adalah; panggilan(), dan Kirim(), di sini terutama panggilan() fungsi ini banyak digunakan untuk melakukan panggilan eksternal serbaguna oleh pengembang.
Meskipun panggilan() dan Kirim() fungsi mengembalikan nilai boolean yang menentukan apakah panggilan berhasil atau tidak. Jadi dalam hal ini, jika salah satu fungsi panggilan() or Kirim() gagal melakukan tugas, mereka akan kembali dengan Salah. Oleh karena itu, jika pengembang tidak memeriksa ulang nilai pengembalian, itu akan menjadi jebakan.
Kerentanan
Perhatikan contoh di bawah ini:
kontrak Lotto{
boolpublic payedOut = salah;
alamat pemenang publik;
jumlah kemenangan uintpublic;
// โฆ fungsi tambahan di sini
fungsi sendToWinner() publik{
membutuhkan(!dibayarOut);
pemenang.send(jumlah menang);
payedOut = benar;
}
fungsi withdrawLeftOver() publik{
membutuhkan (dibayar);
msg.sender.send(ini.saldo);
}
}
Dalam kontrak seperti Lotto di atas, kita dapat mengamati bahwa a pemenang menerima jumlah kemenangan eter meninggalkan sedikit sisa untuk ditarik dari agen eksternal.
Di sini, perangkap untuk kontrak ada di baris [11], di mana a mengirim digunakan tanpa validasi silang dari respon. Dalam contoh di atas, pemenang yang transaksinya gagal (baik karena kekurangan Gas atau jika itu adalah kontrak yang sengaja memasukkan fungsi fallback), memberi wewenang dibayarKeluar untuk diatur ke benar terlepas dari apakah transaksi ether berhasil atau tidak. Dalam acara ini, setiap pengeksploitasi dapat menarik withdraw pemenang kemenangan melalui menarikKiriOver fungsi.
Pendekatan QuillAudit
Tim pengembang internal kami menangani bug ini dengan menggunakan [transfer] fungsi alih-alih [Kirim] berfungsi, karena [transfer] akan kembali jika transaksi eksternal kembali. Dan jika Anda menggunakan [kirim], selalu periksa kembali nilai yang dikembalikan.
Salah satu pendekatan kuat yang kami ikuti adalah memanfaatkan [pola penarikan]. Di sini, kami secara logis mengisolasi fungsi pengiriman eksternal dari basis kode lainnya, dan menempatkan ketegangan transaksi yang berpotensi gagal pada pengguna akhir, karena dialah yang memanggil fungsi penarikan.
2. Masuk Kembali
Kontrak cerdas Ethereum memanggil dan menggunakan kode dari kontrak eksternal lainnya, dan untuk melakukan ini, kontrak diharuskan untuk mengirimkan panggilan eksternal. Panggilan eksternal ini rentan dan rentan terhadap serangan, salah satu serangan tersebut terjadi baru-baru ini dalam kasus peretasan DAO.
Kerentanan
Penyerang melakukan serangan seperti itu ketika kontrak mengirim ether ke alamat yang tidak diketahui. Dalam hal ini, penyerang dapat membuat kontrak di alamat eksternal yang memiliki kode berbahaya dalam fungsi fallback, dan kode berbahaya ini akan dipanggil saat kontrak mengirim eter ke alamat ini.
Fakta: Istilah 'Reentrancy' telah diciptakan dari fakta bahwa ketika kontrak jahat eksternal memanggil fungsi di atas kontrak yang rentan dan kemudian jalur eksekusi kode 'memasukkannya kembali'.
Pertimbangkan contoh di bawah ini, ini adalah brankas Ethereum yang memungkinkan deposan untuk menarik hanya 1 eter per minggu.
kontrak EtherStore {
uint256 penarikan publikLimit = 1 ether;
pemetaan(alamat => uint256) public lastWithdrawTime;
pemetaan (alamat => uint256) neraca publik;
function depositFunds() hutang eksternal {
saldo[pesan.pengirim] += nilai pesan;
}
function withdrawFunds (uint256 _weiToWithdraw) publik {
membutuhkan(saldo[msg.sender] >= _weiToWithdraw);
// batasi penarikan
membutuhkan(_weiToWithdraw <= withdrawalLimit);
// batasi waktu yang diizinkan untuk menarik
membutuhkan (sekarang >= lastWithdrawTime[msg.sender] + 1 minggu);
membutuhkan(msg.sender.call.value(_weiToWithdraw)());
saldo[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = sekarang;
}
}
Dalam kontrak di atas, kami memiliki dua fungsi publik, [depositFunds] dan [withdrawFunds]. [depositFunds] digunakan untuk menambah saldo pengirim, sedangkan [withdrawFunds] menentukan jumlah yang akan ditarik. Dalam hal ini, akan berhasil jika jumlah yang akan ditarik kurang dari 1 eter.
Perangkap di sini terletak pada garis [17] di mana transfer eter terjadi. Penyerang dapat membuat kontrak berbahaya dengan alamat kontrak [EtherStore] sebagai satu-satunya parameter konstruktor. Ini akan membuat [etherStore] menjadi variabel publik, sehingga lebih rentan diserang.
Pendekatan QuillAudit
Kami mengikuti berbagai teknik untuk menghindari potensi kerentanan reentrancy dalam kontrak pintar. Cara pertama dan terbaik yang mungkin adalah penggunaan fungsi [transfer] bawaan saat mentransfer eter ke kontrak eksternal apa pun.
Kedua, penting untuk memastikan bahwa semua perubahan logika dalam variabel keadaan harus dilakukan sebelum mengirim eter keluar dari kontrak. Pada contoh [EtherStore], baris [18] dan [19] harus diletakkan sebelum baris [17].
Teknik ketiga juga dapat digunakan untuk mencegah panggilan masuk kembali; melalui pengenalan mutex. Ini adalah penambahan variabel status yang akan mengunci kontrak selama eksekusi kode.
3. Visibilitas Default
Ada penentu visibilitas untuk fungsi yang kita gunakan di Solidity, dan mereka menentukan cara memanggilnya. Ini adalah visibilitas yang menentukan pemanggilan fungsi; secara eksternal oleh pengguna, dengan kontrak turunan lainnya, hanya secara internal atau hanya secara eksternal. Mari kita lihat bagaimana kesalahan penggunaan penentu visibilitas dapat menyebabkan kerentanan besar dalam kontrak pintar.
Kerentanan
Secara default, visibilitas fungsi adalah [publik], sehingga pengguna eksternal dapat memanggil fungsi tanpa visibilitas khusus. Bug muncul ketika pengembang lupa untuk menentukan visibilitas pada fungsi yang seharusnya bersifat pribadi (atau dapat disebut dalam kontrak itu sendiri). Sebagai contoh;
kontrak HashForEther {
fungsi penarikanKemenangan() {
// Pemenang jika 8 karakter hex terakhir dari alamat adalah 0
membutuhkan(uint32(msg.sender) == 0);
_sendKemenangan();
}
fungsi _sendWinnings() {
msg.sender.transfer(ini.saldo);
}
}
Kontrak di atas adalah permainan bounty menebak alamat yang sederhana. Dalam hal ini, kita dapat melihat bahwa visibilitas fungsi tidak ditentukan, terutama fungsi [ _sendWinnings] adalah [publik] (secara default), maka ini dapat dipanggil melalui alamat apa pun untuk mencuri hadiah.
Pendekatan QuillAudit
Tim internal kami terdiri dari pengembang berpengalaman yang selalu mengikuti praktik audit terbaik, di sini visibilitas fungsi harus ditentukan secara eksplisit, bahkan jika harus disimpan untuk publik, harus disebutkan.
4. Menjaga Penggunaan Konstruktor
Umumnya, Konstruktor disebut fungsi khusus yang digunakan untuk melakukan tugas-tugas penting dan istimewa saat menginisialisasi kontrak. Sebelum Solidity [v0.4.22], konstruktor memegang nama yang sama yang digunakan oleh kontrak yang memuatnya. Sekarang, pertimbangkan kasus di mana nama kontrak diubah selama fase pengembangan tetapi nama konstruktor tetap sama, celah ini juga dapat memberi penyerang akses mudah ke kontrak pintar Anda.
Kerentanan
Ini dapat menyebabkan konsekuensi yang parah jika nama kontrak diubah tetapi nama konstruktor tidak berubah. Sebagai contoh:
kontrak PemilikWallet {
alamat pemilik publik;
// konstruktor
fungsi pemilikWallet(alamat _pemilik) publik {
pemilik = _pemilik;
}
// mundur. Kumpulkan eter.
fungsi () dibayar {}
fungsi penarikan() publik {
membutuhkan(msg.sender == pemilik);
msg.sender.transfer(ini.saldo);
}
}
Dalam kontrak di atas, kita dapat melihat bahwa hanya pemilik yang dapat menarik eter melalui pemanggilan fungsi [penarikan]. Di sini, kerentanan terjadi karena konstruktor dinamai berbeda dari kontrak (huruf pertama berbeda!). Dengan demikian pengeksploitasi dapat memanggil fungsi [ownerWallet] dan mengotorisasi diri mereka sendiri sebagai pemilik, dan kemudian menarik semua ether dalam kontrak dengan memanggil [withdraw].
Pendekatan QuillAudit
Kami mematuhi versi [0.4.22] dari compiler Solidity. Versi ini telah memperkenalkan kata kunci; [constructor] yang memerlukan nama fungsi agar sesuai dengan nama kontrak.
5. Otentikasi Tx.Origin
Di sini, [Tx.Origin] adalah variabel global Solidity, ini berisi alamat akun yang awalnya melakukan panggilan atau transaksi. Variabel ini tidak dapat digunakan untuk otentikasi, karena hal itu membuat kontrak rentan terhadap serangan phishing.
Kerentanan
Kontrak yang mengotorisasi pengguna melalui variabel [tx.origin] terkena serangan eksternal yang mengarahkan pengguna untuk melakukan tindakan yang diautentikasi pada kontrak yang salah. Perhatikan contoh di bawah ini:
kontrak Phishable {
alamat pemilik publik;
konstruktor (alamat _pemilik) {
pemilik = _pemilik;
}
function () hutang eksternal {} // kumpulkan ether
function withdrawAll(alamat _penerima) publik {
membutuhkan(tx.origin == pemilik);
_recipient.transfer(ini.saldo);
}
}
Di sini, di baris [11], kontrak mengizinkan fungsi [withdrawAll] dengan bantuan [tx.origin].
Pendekatan QuillAudit
Kami biasanya menghindari penggunaan [tx.origin] untuk otorisasi dalam kontrak pintar. Meskipun, penggunaan [tx.origin] tidak dilarang, namun memiliki beberapa kasus penggunaan khusus. Kita dapat menggunakan [tx.origin] untuk menolak kontrak eksternal agar tidak memanggil kontrak saat ini, ini dapat dijalankan dengan [require] dalam bentuk [require(tx.origin == msg.sender)]. Hal ini dilakukan untuk menghindari pemanggilan kontrak perantara untuk memanggil kontrak saat ini yang membatasi kontrak ke alamat tanpa kode biasa.
Penutup Akhir
Kami telah secara komprehensif membahas lima perangkap umum dalam bahasa Soliditas. Saat mengembangkan kontrak pintar, kita tidak boleh lupa bahwa mereka tidak dapat diubah menurut desainnya, yang berarti bahwa setelah kita membuatnya, tidak ada cara untuk menambal kode sumber.
Ini merupakan tantangan besar bagi pengembang untuk memanfaatkan alat pengujian dan audit keamanan yang tersedia sebelum penerapan.
Menemukan potensi ancaman berbahaya terhadap kontrak pintar, dan risiko yang beberapa di antaranya kami sebutkan di atas dilakukan dengan cara yang sangat unik dan kuat oleh tim ahli audit internal kami. Kami di QuillAudits melakukan upaya terbaik kami dalam penelitian keamanan untuk menjaga kontrak Anda diperbarui dengan semua praktik keamanan perangkat lunak untuk menjaga kontrak Anda tetap aman dan terlindungi.
Hubungi QuillHash
Dengan kehadiran industri bertahun-tahun, QuillHash telah memberikan solusi perusahaan di seluruh dunia. QuillHash dengan tim ahli adalah perusahaan pengembangan blockchain terkemuka yang menyediakan berbagai solusi industri termasuk perusahaan DeFi, Jika Anda memerlukan bantuan dalam audit kontrak pintar, jangan ragu untuk menghubungi pakar kami di sini!
Ikuti QuillHash untuk pembaruan lebih lanjut
Sumber: https://blog.quillhash.com/2021/06/04/top-5-common-errors-in-solidity-programming-language/
- 11
- Akun
- Keuntungan
- Semua
- Audit
- Otentikasi
- otorisasi
- TERBAIK
- blockchain
- Bug
- bug
- panggilan
- kasus
- Menyebabkan
- menantang
- kode
- Umum
- perusahaan
- kontrak
- kontrak
- terbaru
- DAO
- Defi
- Mendesain
- Pengembang
- pengembang
- Pengembangan
- Enterprise
- Eter
- ethereum
- Acara
- ahli
- keuangan
- Pertama
- mengikuti
- bentuk
- Gratis
- fungsi
- masa depan
- permainan
- GAS
- Aksi
- besar
- terjangan
- di sini
- Seterpercayaapakah Olymp Trade? Kesimpulan
- HTTPS
- besar
- Termasuk
- industri
- IT
- bahasa
- memimpin
- terkemuka
- baris
- Daftar
- Cocok
- Lainnya
- pemilik
- tambalan
- pola
- Phishing
- serangan phishing
- menentukan
- menyajikan
- swasta
- Pemrograman
- publik
- menarik
- penelitian
- tanggapan
- ISTIRAHAT
- aman
- keamanan
- Layanan
- set
- Sederhana
- kecil
- pintar
- kontrak pintar
- Kontrak Cerdas
- So
- Perangkat lunak
- soliditas
- Solusi
- Negara
- sukses
- pengujian
- Sumber
- ancaman
- waktu
- puncak
- top 5
- .
- Transaksi
- us
- Pengguna
- nilai
- Kubah
- jarak penglihatan
- Kerentanan
- kerentanan
- Rentan
- minggu
- SIAPA
- dalam
- tahun