Serangan reentrancy merupakan salah satu ancaman keamanan yang paling signifikan dalam pengembangan kontrak pintar. Analisis teknis ini menjelaskan mekanisme di balik kerentanan reentrancy dan menyediakan strategi pertahanan yang komprehensif untuk melindungi kontrak Anda.
Apa itu Serangan Reentrancy?
Reentrancy terjadi ketika sebuah fungsi dalam kontrak pintar dapat terganggu selama eksekusinya dan dipanggil kembali sebelum pemanggilan pertama selesai. Dalam istilah teknis, reentrancy mengeksploitasi konteks eksekusi dari kontrak pintar dengan memanipulasi alur kontrol melalui panggilan eksternal.
Ketika Kontrak A berinteraksi dengan Kontrak B, kerentanan muncul karena Kontrak B dapat memanggil kembali ke Kontrak A sementara eksekusi Kontrak A masih berlangsung. Pola pemanggilan rekursif ini dapat dimanfaatkan untuk memanipulasi status kontrak dan menguras dana.
Mekanika Serangan: Bagaimana Reentrancy Bekerja
Pertimbangkan skenario dengan dua kontrak:
Kontrak A: Kontrak yang rentan yang menyimpan 10 ETH
Kontrak B: Sebuah kontrak jahat dengan 1 ETH disetorkan di Kontrak A
Alur serangan mengikuti pola ini:
Kontrak B memanggil fungsi withdraw() di Kontrak A
Kontrak A memverifikasi bahwa saldo Kontrak B lebih besar dari 0 (lulus pemeriksaan)
Kontrak A mengirim 1 ETH ke Kontrak B sebelum memperbarui catatan saldonya
Transfer ETH memicu fungsi fallback dari Kontrak B
Di dalam fungsi fallback, Kontrak B memanggil penarikan Kontrak A lagi ()
Karena Kontrak A belum memperbarui saldo Kontrak B, pemeriksaan berhasil lagi.
Kontrak A mengirimkan ETH lain ke Kontrak B
Siklus ini diulang sampai Kontrak A kehabisan dana
Kerentanan kritis terletak pada urutan eksekusi Kontrak A: ia melakukan panggilan eksternal ( mengirim ETH) sebelum memperbarui keadaan internalnya ( mengatur saldo menjadi nol).
Tiga Teknik Pertahanan Terhadap Reentrancy
1. Perlindungan Tingkat Fungsi dengan Modifier noReentrant
Modifier noReentrant mengimplementasikan mekanisme penguncian yang mencegah fungsi dipanggil secara rekursif:
solidity
// Variabel status untuk melacak reentrancy
bool private locked = false;
// Fungsi terlindungi
fungsi tarik() publik noReentrant {
// Logika fungsi di sini
}
Pendekatan ini memblokir upaya reentrancy dengan mempertahankan variabel status yang berlaku untuk seluruh kontrak yang mencegah eksekusi bersamaan dari fungsi-fungsi yang dilindungi.
2. Pola Cek-Efek-Interaksi
Pola ini merestrukturisasi kode untuk mengikuti urutan operasi tertentu:
Periksa: Verifikasi kondisi ( misalnya, saldo > 0)
Efek: Memperbarui variabel status ( misalnya, set saldo = 0)
Interaksi: Lakukan panggilan eksternal (misalnya, transfer ETH)
Membandingkan kode yang rentan vs. kode yang dilindungi:
Rentan:
solidity
fungsi withdraw() eksternal {
uint bal = balances[msg.sender];
require(bal > 0);
// Interaksi sebelum Efek (vulnerable)
(bool sent, ) = msg.sender.call{value: bal}("");
require(sent, "Gagal mengirim Ether");
balances[msg.sender] = 0; // Mungkin tidak pernah tercapai jika terjadi reentrancy
}
Dilindungi:
soliditas
fungsi withdraw() eksternal {
uint bal = balances[msg.sender];
require(bal > 0);
// Menggunakan penjaga dalam sebuah kontrak
kontrak ProtectedContract adalah GlobalReentrancyGuard {
fungsi protectedFunction() eksternal {
_beforeNonReentrant();
// Logika fungsi yang dilindungi di sini
_setelahNonReentrant();
}
}
Teknik ini mencegah reentrancy lintas kontrak dengan mempertahankan registri status global yang melacak status eksekusi di berbagai kontrak dalam ekosistem Anda.
Praktik Terbaik Keamanan
Untuk memastikan perlindungan menyeluruh terhadap serangan reentrancy:
Terapkan beberapa lapisan pertahanan: Gabungkan pola pemeriksaan-efek-interaksi dengan penjaga reentrancy untuk keamanan maksimum
Lakukan pengujian menyeluruh: Gunakan alat khusus seperti Mythril untuk mendeteksi potensi kerentanan reentrancy
Ikuti pola yang telah ditetapkan: Terapkan langkah-langkah keamanan secara konsisten di semua kontrak dalam proyek Anda
Gunakan ketergantungan yang diaudit: Sertakan pustaka yang telah teruji dengan catatan keamanan yang terbukti
Perbarui saldo terlebih dahulu: Selalu ubah status sebelum melakukan panggilan eksternal atau transfer
Dengan menerapkan mekanisme pertahanan ini, Anda dapat secara efektif melindungi kontrak pintar Anda dari salah satu vektor serangan paling berbahaya dalam keamanan blockchain.
Halaman ini mungkin berisi konten pihak ketiga, yang disediakan untuk tujuan informasi saja (bukan pernyataan/jaminan) dan tidak boleh dianggap sebagai dukungan terhadap pandangannya oleh Gate, atau sebagai nasihat keuangan atau profesional. Lihat Penafian untuk detailnya.
Keamanan Smart Contract: Memahami dan Mencegah Kerentanan Reentrancy
Serangan reentrancy merupakan salah satu ancaman keamanan yang paling signifikan dalam pengembangan kontrak pintar. Analisis teknis ini menjelaskan mekanisme di balik kerentanan reentrancy dan menyediakan strategi pertahanan yang komprehensif untuk melindungi kontrak Anda.
Apa itu Serangan Reentrancy?
Reentrancy terjadi ketika sebuah fungsi dalam kontrak pintar dapat terganggu selama eksekusinya dan dipanggil kembali sebelum pemanggilan pertama selesai. Dalam istilah teknis, reentrancy mengeksploitasi konteks eksekusi dari kontrak pintar dengan memanipulasi alur kontrol melalui panggilan eksternal.
Ketika Kontrak A berinteraksi dengan Kontrak B, kerentanan muncul karena Kontrak B dapat memanggil kembali ke Kontrak A sementara eksekusi Kontrak A masih berlangsung. Pola pemanggilan rekursif ini dapat dimanfaatkan untuk memanipulasi status kontrak dan menguras dana.
Mekanika Serangan: Bagaimana Reentrancy Bekerja
Pertimbangkan skenario dengan dua kontrak:
Alur serangan mengikuti pola ini:
Kerentanan kritis terletak pada urutan eksekusi Kontrak A: ia melakukan panggilan eksternal ( mengirim ETH) sebelum memperbarui keadaan internalnya ( mengatur saldo menjadi nol).
Tiga Teknik Pertahanan Terhadap Reentrancy
1. Perlindungan Tingkat Fungsi dengan Modifier noReentrant
Modifier noReentrant mengimplementasikan mekanisme penguncian yang mencegah fungsi dipanggil secara rekursif:
solidity // Variabel status untuk melacak reentrancy bool private locked = false;
// Modifikasi untuk mencegah reentrancy modifier noReentrant() { require(!locked, "Reentrant call"); terkunci = true; _; terkunci = false; }
// Fungsi terlindungi fungsi tarik() publik noReentrant { // Logika fungsi di sini }
Pendekatan ini memblokir upaya reentrancy dengan mempertahankan variabel status yang berlaku untuk seluruh kontrak yang mencegah eksekusi bersamaan dari fungsi-fungsi yang dilindungi.
2. Pola Cek-Efek-Interaksi
Pola ini merestrukturisasi kode untuk mengikuti urutan operasi tertentu:
Membandingkan kode yang rentan vs. kode yang dilindungi:
Rentan: solidity fungsi withdraw() eksternal { uint bal = balances[msg.sender]; require(bal > 0);
}
Dilindungi: soliditas fungsi withdraw() eksternal { uint bal = balances[msg.sender]; require(bal > 0);
}
Dengan memperbarui status sebelum interaksi eksternal, kontrak tetap aman meskipun panggilan eksternal memicu panggilan fungsi reentrant.
3. Perlindungan Lintas Kontrak dengan GlobalReentrancyGuard
Untuk proyek dengan beberapa kontrak yang saling berinteraksi, pengaman reentrancy bersama memberikan perlindungan yang komprehensif:
solidity // Kontrak pusat untuk perlindungan reentrancy kontrak GlobalReentrancyGuard { mapping(alamat => bool) pribadi _status;
}
// Menggunakan penjaga dalam sebuah kontrak kontrak ProtectedContract adalah GlobalReentrancyGuard { fungsi protectedFunction() eksternal { _beforeNonReentrant();
}
Teknik ini mencegah reentrancy lintas kontrak dengan mempertahankan registri status global yang melacak status eksekusi di berbagai kontrak dalam ekosistem Anda.
Praktik Terbaik Keamanan
Untuk memastikan perlindungan menyeluruh terhadap serangan reentrancy:
Dengan menerapkan mekanisme pertahanan ini, Anda dapat secara efektif melindungi kontrak pintar Anda dari salah satu vektor serangan paling berbahaya dalam keamanan blockchain.