Panduan Utama untuk EOS Smart Contract Security. Komunitas crypto menjadi skeptis ketika ICO terbesar di Dunia, EOS diluncurkan pada Juni 2018 dan dibekukan selama 2 hari karena bug perangkat lunak. Tetapi maju cepat 4 bulan dan EOS hari ini menyumbang lebih dari menggandakan transaksi yang dilakukan Ethereum hari ini. Melalui janji transaksi gratis dan lebih cepat, Dapp EOS teratas memiliki sekitar 13.000 pengguna aktif harian dibandingkan dengan hanya 2.000 Dapp teratas Ethereum.

Keamanan Kontrak Cerdas EOS

Oleh Rohan Agarwal

Beberapa kerentanan kontrak pintar umum berlaku untuk hampir semua platform. Seperti Ethereum, kontrak pintar yang ditulis pada EOS perlu diaudit sebelum ditayangkan di mainnet. Bug fatal dalam kontrak dapat dieksploitasi jika kontrak tidak cukup teruji. Dalam panduan ini, kami akan membantu Anda menghindari kesalahan umum dalam perjalanan Anda membuat dApp pembunuh berikutnya pada EOS.

Sebelum Anda membaca panduan ini, penting untuk mengetahui tentang beberapa informasi prasyarat mengenai pengembangan EOS yang akan berguna saat Anda membaca panduan ini. Pengetahuan tentang C ++ adalah suatu keharusan. Tempat terbaik untuk memulai pengembangan kontrak pintar adalah milik EOSIO dokumentasi

Berurusan dengan Dispatcher ABI

eksternal "C" {

batal berlaku (penerima uint64_t, kode uint64_t, tindakan uint64_t) {

class_name thiscontract (receiver);

if ((code == N (eosio.token)) && (tindakan == N (transfer))) {

eksekusi_aksi (&kontrak ini, &class_name :: transfer);

kembali;

}

if (code! = receiver) return;

switch (tindakan) {EOSIO_API (class_name, (action_1) (action_n))};

eosio_exit (0);

}

}

Gambar di atas adalah contoh kode operator ABI yang dimodifikasi. Dispatcher ABI yang lebih sederhana seperti yang ditunjukkan di bawah ini digunakan untuk penanganan tindakan kontrak yang lebih sederhana.

EOSIO_ABI (class_name, (action_1) (action_n));

Dispatcher / forwarder ABI memungkinkan kontrak untuk mendengarkan peristiwa transfer eosio.token yang masuk, serta interaksi normal dengan smart contract. Penting untuk mengikat setiap tindakan dan kode utama untuk memenuhi persyaratan, untuk menghindari panggilan yang tidak normal dan ilegal.

Contohnya adalah peretasan yang terjadi pada dApp Kasino EOSBet karena bug dalam kode sumber penerusan ABI mereka.

if (code == self || code == N (eosio.token)) {

TIPE thiscontract (self);

saklar (tindakan) {

EOSIO_API (TYPE, MEMBERS)

}

}

Pemeriksaan di atas pada penangan tindakan terapan dari kode sumber penerusan ABI memungkinkan penyerang untuk melewati fungsi eosio.token :: transfer () sepenuhnya, dan langsung memanggil fungsi contract :: transfer () tanpa mentransfer EOS ke kontrak sebelum menempatkan bertaruh. Untuk kerugian, dia tidak dibayar apa-apa, tapi tidak kehilangan apa-apa. Namun, untuk kemenangan, dia dibayar EOS asli dari kontrak.

Mereka memperbaiki bug di atas dengan menambahkan cek dari tindakan pengalihan kontrak eosio.token sebelum tindakan yang masuk meminta ke kontrak.

if (code == self || code == N (eosio.token)) {

if (aksi == N (transfer)) {

eosio_assert (kode == N (eosio.token), "Harus mentransfer EOS");

}

TIPE thiscontract (self);

saklar (tindakan) {

EOSIO_API (TYPE, MEMBERS)

}

}

Penting untuk menggunakan pernyataan require_auth (akun); menjadi tindakan yang Anda hanya ingin akun yang diotorisasi untuk mengeksekusinya. membutuhkan_auth (_self); digunakan untuk memberi otorisasi hanya kepada pemilik kontrak untuk menandatangani transaksi

Otorisasi dalam Tindakan

void token :: transfer (nama_akun dari, nama_akun ke, jumlah aset)

{

auto sym = quantity.symbol.name ();

need_recipient (dari);

need_recipient (untuk);

pembayar otomatis = has_auth (ke)? untuk dari;

sub_balance (dari, kuantitas);

add_balance (kepada, kuantitas, pembayar);

}

Kode contoh di atas memungkinkan siapa saja untuk melakukan tindakan. Untuk mengatasinya, gunakan require_auth (from); pernyataan untuk memberi otorisasi pembayar untuk melakukan tindakan.

Cobalah untuk menghindari memodifikasi kontrak eosio.token

Seorang hacker topi putih baru-baru ini berhasil melakukannya klaim 1 miliar token dari dapp karena panggilan metode yang tidak teruji dengan baik dalam kontrak eosio.token mereka. Dapp Se7ens (sekarang tidak aktif) menyatakan metode baru di dalam kontrak eosio.token untuk mengirimkan token mereka ke akun pengguna. Kontrak tidak menyebut masalah atau tindakan transfer kontrak eosio.token untuk mencerminkan perubahan dan karenanya dana secara ajaib muncul di akun pengguna. Kedua, mereka lupa untuk memverifikasi jumlah dalam metode sebelum transfer yang memungkinkan peretas mengklaim 1 miliar token mereka dalam prosesnya..

Selain mengubah suplai maksimum dan simbol token, disarankan untuk tidak memodifikasinya untuk fungsi khusus karena bug dalam kontrak eosio.token bisa berakibat fatal. Untuk memfasilitasi airdrop dengan aman, transfer token airdrop ke akun terpisah dan distribusikan dari sana.

Modifikasi properti tabel multi-indeks

EOS saat ini menyimpan data ke database memori bersama untuk dibagikan di seluruh tindakan.

struct [[eosio :: table]] orang {

kunci nama_kun;

std :: string first_name;

std :: string last_name;

std :: string street;

std :: kota string;

std :: negara string;

uint64_t primary_key () const {kunci kembali; }

};

typedef eosio :: multi_index<N (orang), orang> address_index;

Contoh kode di atas membuat tabel multi_index bernama orang yang didasarkan pada struktur data dari satu baris tabel itu menggunakan struct person. EOS saat ini tidak mengizinkan modifikasi properti tabel setelah diterapkan. Kegagalan pernyataan eosio_assert_message akan menjadi kesalahan yang akan dilemparkan. Oleh karena itu, properti perlu dipikirkan secara menyeluruh sebelum penerapan tabel. Jika tidak, tabel baru dengan nama berbeda perlu dibuat dan sangat hati-hati saat bermigrasi dari tabel lama ke yang baru. Kegagalan melakukan dapat mengakibatkan hilangnya data.

Pemeriksaan Numerical Overflow

Saat melakukan operasi aritmatika, nilai dapat meluap jika kondisi batas tidak diperiksa dengan cukup bertanggung jawab, menyebabkan hilangnya aset pengguna.

batal transfer (simbol nama_simbol, nama_akun dari, nama_akun ke, saldo uint64_t) {

require_auth (dari);

akun dari akun;

eosio_assert (is_balance_within_range (keseimbangan), "saldo tidak valid");

eosio_assert (keseimbangan > 0, "harus mentransfer keseimbangan positif"); jumlah uint64_t = saldo * 4; // Perkalian melimpah

}

Pada kode contoh di atas, menggunakan uint64_t untuk menunjukkan keseimbangan pengguna dapat menyebabkan luapan saat nilainya dikalikan. Oleh karena itu hindari penggunaan uint64_t untuk menunjukkan saldo dan melakukan operasi aritmatika sejauh mungkin. Gunakan struktur aset yang ditentukan di eosiolib untuk operasi daripada keseimbangan tepat yang menangani kondisi luapan.

Menjaga Asumsi dalam Kontrak

Akan ada asumsi yang membutuhkan asersi selama pelaksanaan kontrak. Menggunakan eosio_assert akan menangani kondisi sebelumnya dan menghentikan eksekusi tindakan tertentu jika pernyataan gagal. Sebagai contoh –

batal assert_roll_under (const uint8_t& roll_under) {

eosio_assert (roll_under >= 2 && roll_under <= 96,

"roll under overflow, harus lebih besar dari 2 dan kurang dari 96");

}

Pernyataan assert di atas membuat asumsi bahwa roll_under integer lebih besar dari 2 & kurang dari 96. Tetapi jika tidak, buang pesan di atas dan hentikan eksekusi. Gagal menemukan kasus sudut seperti di atas bisa menjadi bencana bagi rumah yang menetapkan aturan.

Menghasilkan angka Acak Benar

Menghasilkan angka True Random di EOS Blockchain masih berisiko jika tidak dilakukan secara akurat. Kegagalan untuk melakukannya dengan benar akan mengakibatkan musuh memprediksi hasil, mempermainkan seluruh sistem dalam prosesnya. Layanan seperti Oracalize.it ada untuk memberikan nomor acak dari sumber eksternal tetapi harganya mahal dan satu titik kegagalan. Orang-orang telah menggunakan variabel kontekstual Blockchain (nomor blok, stempel blok, dll.) Di masa lalu untuk menghasilkan nomor acak dalam kontrak pintar Ethereum, tetapi sudah bermain game sebelumnya. Untuk melakukan pembangkitan dengan benar, program harus menyediakan semacam keacakan gabungan yang tidak dapat dikontrol oleh satu pihak pun. Salah satu cara terbaik yang mungkin dilakukan saat ini adalah metode yang disarankan oleh Dan Larimar sendiri ketika menghasilkan angka acak antara dua pihak.

BountyOne Blog: Keamanan Kontrak Cerdas EOS

string sha256_to_hex (const checksum256& sha256) {

kembali ke_hex ((char *) sha256.hash, sizeof (sha256.hash));

}

string sha1_to_hex (const checksum160& sha1) {

kembali ke_hex ((char *) sha1.hash, sizeof (sha1.hash));

}

template <kelas T>

Void hash_combine sebaris (std :: size_t& benih, const T& v) {

std :: hash<T> penggiling daging;

seed ^ = hasher (v) + 0x9e3779b9 + (seed << 6) + (biji >> 2);

}

Kode contoh di atas memberikan pembangkitan bilangan acak yang dioptimalkan antara 1 sampai 100. seed1 adalah benih rumah dan seed2 adalah benih pengguna di atas. Sebagai referensi, Dappub dan EOSBetCasino telah membuka sumber kontrak lengkap mereka dengan penerapan generator nomor acak dari permainan dadu yang adil antara pemain dan rumah (pengembang).

uint8_t compute_random_roll (const checksum256& seed1, const checksum160& seed2) {

size_t hash = 0;

hash_combine (hash, sha256_to_hex (seed1));

hash_combine (hash, sha1_to_hex (seed2));

kembali hash% 100 + 1;

}

EOSBet baru saja mendapatkannya diretas lagi dari 65.000 EOS ketika musuh menipu kontrak eosio.token mereka untuk mengirim EOS ke dompetnya setiap kali dia bertransaksi di antara dompetnya sendiri. Kode kontrak eosio.token memberi tahu baik pengirim maupun penerima token EOS yang ada token masuk. Untuk meniru perilaku & memfasilitasi peretasan, musuh membuat dua akun, anggap saja A & B. A memiliki kontrak pintar dengan tindakan yang memiliki pernyataan require_recipient (N (eosbetdice11)). Ketika A memfasilitasi transaksi dari A ke B melalui panggilan tindakan, itu memberi tahu fungsi transfer dalam kontrak seolah-olah panggilan itu berasal dari kontrak eosio.token. Karena tidak ada transfer nyata EOS ke dalam kontrak, setiap kali peretas kehilangan taruhan, dia tidak kehilangan apa-apa, tetapi dia diberi hadiah ketika memenangkan taruhan. Karenanya, memeriksa nama kontrak dan nama tindakan saja tidak cukup.

Memeriksa pemberitahuan dari Kontrak

Untuk mengurangi masalah ini, fungsinya harus memeriksa apakah kontrak tersebut memang penerima token atau bukan.

eosio_assert (transfer_data.from == _self || transfer_data.to == _self, "Harus transfer masuk atau keluar");

Apa praktik terbaik yang harus diikuti seseorang saat mengembangkan kontrak pintar pada EOS?

Bug adalah bagian tak terhindarkan dari perangkat lunak apa pun. Konsekuensinya diperkuat dalam lingkungan yang terdesentralisasi terutama jika itu melibatkan transaksi nilai. Terlepas dari perlindungan khusus EOS yang dibahas di atas, berikut adalah beberapa tindakan pencegahan umum dan praktik terbaik yang harus diingat oleh pengembang kontrak pintar baru –

  1. Selalu audit kontrak secara independen dari firma audit kontrak pintar pihak ketiga sebelum merilis di mainnet.
  2. Lakukan proses debug Caveman yang diperlukan (satu-satunya cara untuk men-debug kontrak saat ini) dari kontrak sebelum merilis ke testnet. Dokumentasi EOSIO memiliki a panduan hebat untuk itu.
  3. Tetapkan batas kecepatan transfer pada penarikan untuk menghindari kerugian yang berlebihan pada hari-hari awal peluncuran mainnet. Memiliki program bug bounty untuk pengungkapan yang bertanggung jawab oleh peretas topi putih.
  4. Miliki tombol pemutus untuk membekukan kontrak ketika bug terdeteksi.

Untuk mengimplementasikannya, kami mempertahankan sebuah flag di tabel multi_index. Kami menetapkan bendera menggunakan tindakan yang hanya dapat dipanggil oleh pemilik kontrak. Dan kemudian kami memeriksa setiap tindakan publik apakah bendera disetel untuk dibekukan atau tidak. Contoh implementasi fungsi diberikan di bawah ini.

struct st_freeze {

uint64_t dibekukan;

};

typedef singleton<N (beku), st_beku> tb_freeze;

tb_freeze _freeze;

uint64_t getFreezeFlag () {

st_freeze_st beku {.freeze = 0};

return _freeze.get_or_create (_self, frozen_st);

}

void setFreezeFlag (const uint64_t& pFreeze) {

st_freeze frozen_st = getFreezeFlag ();

frozen_st.freeze = pFreeze;

_freeze.set (frozen_st, _self);

}

// Aksi publik

void freeze () {

membutuhkan_auth (_self);

setFreezeFlag (1);

}

// Aksi publik

batalkan pembekuan () {

membutuhkan_auth (_self);

setFreezeFlag (0);

}

// tindakan publik apa pun

batal aksi (…) {

eosio_assert (getFreezeFlag (). beku == 1, "Kontrak dibekukan!");

}

  1. Tetap perbarui tentang peningkatan keamanan di perpustakaan atau pengungkapan kerentanan di platform. Perbarui perpustakaan Anda bila perlu segera.
  2. Buka sumber kode kontrak setidaknya sehingga keadilan dipertahankan dalam game dan pengembang indie dapat membantu menemukan bug lebih cepat.

Keamanan Kontrak Cerdas EOS: Kesimpulan

Baru 5 bulan berlalu sejak peluncuran EOS, namun telah berkembang melampaui ekspektasi. Pengorbanan yang telah dibuatnya – DPOS, kontrak pintar yang bisa berubah, 21 node penambangan dll pasti menghadapi kritik keras dari maksimalis desentralisasi. Namun demikian, ini tidak menghentikan dApps yang berbasis pada Ethereum untuk beralih ke EOS mengingat skalabilitas yang ditawarkan platform tersebut hari ini. Apakah itu EOS atau Ethereum yang memenangkan perang, masih belum diputuskan, tetapi EOS sudah pasti memenangkan pertempuran tersebut. Dan itu akan tetap sama sampai Ethereum berhasil mencapai skalabilitas yang dibutuhkan dunia untuk menjalankan “The World Computer”.

_________________________________________________________________________________________

Artikel ini ditulis oleh Rohan Agarwal

Bio – #Android Dev # Entrepreneur # Blockchain Dev & Peneliti Co-founder @ Cypherock.com – Dompet perangkat keras yang aman untuk Ponsel Cerdas.

Linkedin – https://www.linkedin.com/in/rohanagarwal94/

Github – https://github.com/rohanagarwal94

Indonesia – https://twitter.com/rohanagarwal94

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me