Dasar
Spot
Perdagangkan kripto dengan bebas
Perdagangan Margin
Perbesar keuntungan Anda dengan leverage
Konversi & Investasi Otomatis
0 Fees
Perdagangkan dalam ukuran berapa pun tanpa biaya dan tanpa slippage
ETF
Dapatkan eksposur ke posisi leverage dengan mudah
Perdagangan Pre-Market
Perdagangkan token baru sebelum listing
Futures
Akses ribuan kontrak perpetual
TradFi
Emas
Satu platform aset tradisional global
Opsi
Hot
Perdagangkan Opsi Vanilla ala Eropa
Akun Terpadu
Memaksimalkan efisiensi modal Anda
Perdagangan Demo
Pengantar tentang Perdagangan Futures
Bersiap untuk perdagangan futures Anda
Acara Futures
Gabung acara & dapatkan hadiah
Perdagangan Demo
Gunakan dana virtual untuk merasakan perdagangan bebas risiko
Peluncuran
CandyDrop
Koleksi permen untuk mendapatkan airdrop
Launchpool
Staking cepat, dapatkan token baru yang potensial
HODLer Airdrop
Pegang GT dan dapatkan airdrop besar secara gratis
Launchpad
Jadi yang pertama untuk proyek token besar berikutnya
Poin Alpha
Perdagangkan aset on-chain, raih airdrop
Poin Futures
Dapatkan poin futures dan klaim hadiah airdrop
Investasi
Simple Earn
Dapatkan bunga dengan token yang menganggur
Investasi Otomatis
Investasi otomatis secara teratur
Investasi Ganda
Keuntungan dari volatilitas pasar
Soft Staking
Dapatkan hadiah dengan staking fleksibel
Pinjaman Kripto
0 Fees
Menjaminkan satu kripto untuk meminjam kripto lainnya
Pusat Peminjaman
Hub Peminjaman Terpadu
Kerentanan Reentrancy: Cara Mengidentifikasi, Mengeksploitasi, dan Mencegahnya
Dalam dunia kontrak pintar, reentrancy dianggap sebagai salah satu celah paling berbahaya. Artikel ini akan membantu Anda tidak hanya memahami apa itu serangan reentrancy, tetapi juga cara melindunginya secara efektif. Dari teknik dasar hingga solusi tingkat lanjut, kita akan menjelajahi berbagai cara untuk melindungi seluruh proyek Anda.
Bagaimana Reentrancy Berfungsi: Mekanisme Serangan Dasar
Untuk memahami reentrancy, pertama-tama kita perlu memahami konsep dasar: sebuah kontrak pintar dapat memanggil kontrak lain, dan saat itu, kontrak kedua dapat memanggil kembali kontrak pertama saat masih dalam proses eksekusi.
Bayangkan Anda memiliki dua kontrak: ContractA menyimpan 10 Ether dan ContractB telah mengirimkan 1 Ether ke sana. Ketika ContractB memanggil fungsi penarikan, akan diperiksa apakah saldo cukup. Jika ya, Ether akan dikirim kembali ke ContractB. Pada titik ini, jika tidak ada langkah perlindungan yang tepat, inilah celah yang bisa dimanfaatkan penyerang.
Dalam serangan reentrancy tipikal, penyerang membutuhkan dua fungsi: attack() untuk memulai serangan, dan fallback() untuk melakukan panggilan kembali. Fungsi fallback adalah fungsi khusus dalam Solidity — tidak memiliki nama, tidak memiliki parameter, dan akan dipanggil otomatis setiap kali Ether dikirim ke kontrak tanpa data apa pun.
Langkah-langkah Melakukan Serangan Reentrancy
Ikuti proses serangan secara berurutan. Penyerang memanggil fungsi attack() dari kontraknya sendiri. Di dalam fungsi ini, ia akan memanggil fungsi withdraw() dari ContractA.
Ketika ContractA menerima panggilan ini, ia memeriksa apakah ContractB memiliki saldo lebih dari 0. Jika ya, Ether akan dikirim kembali ke ContractB, memicu fungsi fallback-nya. Pada saat ini, ContractA tersisa 9 Ether, tetapi yang lebih penting — saldo ContractB dalam catatan kontrak masih belum diperbarui ke 0.
Ini adalah masalah: fallback() memanggil withdraw() dari ContractA lagi. ContractA memeriksa kembali saldo ContractB — masih 1 Ether! Kenapa? Karena baris balance[msg.sender] = 0 belum pernah dieksekusi, karena berada setelah pengiriman Ether.
Proses ini berulang: panggilan withdraw → pemeriksaan saldo (masih > 0) → pengiriman Ether → fallback() dipicu → panggilan withdraw lagi… sampai seluruh Ether ContractA berhasil ditarik.
Analisis Kode: Ketika Reentrancy Menjadi Kenyataan
Contract EtherStore adalah contoh kontrak yang rentan terhadap serangan. Ia memiliki fungsi deposit() untuk menyimpan saldo dan withdrawAll() untuk menarik uang. Masalahnya terletak pada cara withdrawAll() diimplementasikan: memeriksa kondisi, mengirim Ether, lalu memperbarui saldo.
Kontrak Attack akan memanfaatkan celah ini. Dalam konstruktor, penyerang mengirimkan alamat EtherStore, sehingga dapat memanggil fungsi-fungsinya. Fungsi fallback dari kontrak Attack akan dipanggil setiap kali EtherStore mengirim Ether, dan di dalamnya akan terus memanggil kembali withdrawAll() selama masih ada Ether. Fungsi attack() memulai proses dengan mengirim 1 Ether pertama ke EtherStore untuk melewati pemeriksaan awal.
Hasilnya, seluruh dana EtherStore berhasil ditarik dalam satu transaksi.
Tiga Strategi Melindungi Kontrak dari Reentrancy
Untuk melindungi kontrak pintar, ada tiga tingkat perlindungan berbeda, dari dasar hingga lengkap.
Contoh noReentrant: Solusi Perlindungan Dasar
Metode paling sederhana adalah menggunakan modifier noReentrant(). Modifier adalah jenis fungsi khusus dalam Solidity yang memungkinkan Anda mengubah perilaku fungsi lain tanpa menulis ulang seluruhnya.
Ide sederhananya: saat sebuah fungsi dilindungi oleh noReentrant(), kontrak akan dikunci selama proses eksekusi. Setiap panggilan yang mencoba masuk kembali ke fungsi ini akan gagal karena variabel status kunci tidak mengizinkan. Hanya setelah fungsi selesai dan dibuka kunci, panggilan lain dapat berhasil.
Solusi ini sangat efektif untuk melindungi satu fungsi, tetapi tidak menangani kasus yang lebih kompleks.
Contoh Check-Effect-Interaction: Mencegah Reentrancy Multi-Fungsi
Teknik kedua yang lebih kuat: menerapkan pola Check-Effect-Interaction. Alih-alih melindungi satu fungsi, pola ini mengubah cara Anda menulis logika fungsi.
Prinsip utamanya adalah: periksa kondisi terlebih dahulu (Check), perbarui status segera setelahnya (Effect), lalu berinteraksi dengan kontrak eksternal (Interaction). Ini mencegah penyerang memanfaatkan dengan memanggil kembali, karena saat mereka memanggil lagi, saldo sudah diperbarui menjadi 0.
Alih-alih memperbarui balance[msg.sender] = 0 setelah mengirim Ether, pindahkan ke sebelum pengiriman. Dengan begitu, meskipun fallback() memanggil kembali, pemeriksaan akan selalu gagal karena saldo sudah 0.
Metode ini melindungi kontrak dari reentrancy secara menyeluruh, bahkan saat ada banyak fungsi penarikan uang berbeda.
GlobalReentrancyGuard: Perlindungan Menyeluruh di Seluruh Proyek
Untuk proyek yang kompleks dengan banyak kontrak yang berinteraksi, kita membutuhkan solusi yang lebih lengkap: GlobalReentrancyGuard.
Alih-alih mengunci di tingkat fungsi, solusi ini mengunci di tingkat seluruh proyek. Anda membuat kontrak terpisah yang menyimpan variabel status kunci bersama, dan semua kontrak lain dalam proyek merujuk ke sana.
Bayangkan skenario ini: penyerang memanggil fungsi dalam kontrak ScheduledTransfer. Setelah melewati pemeriksaan, ia mengirim Ether ke AttackTransfer. Fungsi fallback AttackTransfer diaktifkan dan berusaha memanggil kembali ScheduledTransfer. Tetapi karena GlobalReentrancyGuard telah mengunci status secara global, panggilan ini dicegah.
Metode ini sangat berguna untuk proyek besar dengan banyak kontrak, di mana reentrancy bisa terjadi antar kontrak yang berbeda.
Memilih Teknik yang Tepat untuk Proyek Anda
Pilihan strategi tergantung pada kompleksitas proyek. Jika kontrak Anda memiliki sedikit fungsi interaksi, noReentrant() sudah cukup efektif. Jika ada banyak fungsi penarikan, pola Check-Effect-Interaction adalah pilihan terbaik. Untuk proyek besar dengan banyak kontrak, GlobalReentrancyGuard memberikan perlindungan lengkap.
Tidak peduli apa yang Anda pilih, hal utama adalah memahami bagaimana reentrancy bekerja, agar Anda dapat mengenali dan mencegahnya secara proaktif.
Untuk pembaruan harian tentang keamanan kontrak pintar, memeriksa kode sumber, dan tren terbaru di bidang Web3, ikuti sumber daya mendalam tentang keamanan Solidity.