Securing Secret Key: Eksperimen untuk Menemukan Cara Terbaik dalam Mengamankan Secret Key di Android

oleh Lalu Raynaldi Pratama Putra dan Meyta Zenis Taliti

Pendahuluan

Dalam pengembangan aplikasi Android, menjaga keamanan secret key menjadi tantangan yang sering dihadapi oleh developer. Secret key yang disimpan dengan cara yang kurang aman dapat dengan mudah terkespos, berpotensi membuka celah bagi attacker untuk mengeksploitasi aplikasi.

Banyak metode telah direkomendasikan untuk menyembunyikan Secret Key, mulai dari menyimpannya di BuildConfig, menggunakan Jetpack Security Library, hingga menerapkan Native Library. Namun, seberapa efektif masing-masing metode dalam menghadapi serangan sebenarnya?

Artikel ini akan mengeksplorasi dan menguji beberapa teknik yang umum digunakan untuk menyembunyikan secret key. Dengan pendekatan eksperimental, kita akan mengevaluasi tiap metode dari perspektif developer maupun attacker. Salah satu tools utama yang akan digunakan adalah Frida, yang memungkinkan kita menguji seberapa mudah sebuah aplikasi dapat diretas.

Tujuan dari eksperimen ini adalah untuk menunjukkan bahwa informasi sensitif dalam aplikasi Android harus ditangani dengan serius. Jika tidak, seorang attacker yang memiliki akses ke source code atau aplikasi kita dapat mengeksploitasi celah keamanan yang ada.

Meskipun artikel ini menawarkan eksplorasi berbagai metode perlindungan, penting untuk diingat bahwa tidak ada solusi yang benar-benar bulletproof. Oleh karena itu, mengikuti security best practices tetap menjadi langkah terbaik dalam menjaga keamanan informasi sensitif.

Metode

Dalam eksperimen ini, kita akan menguji tiga metode penyimpanan secret key dengan tingkat keamanan yang berbeda:

  1. Easy: Menyimpan secret key di file properties.

  2. Medium: Menggunakan kombinasi Native Library dan EncryptedSharedPreferences dari Jetpack Security Library.

  3. Hard: Menggunakan kombinasi Native Library, Base64 Encryption, dan EncryptedFile dari Jetpack Security Library.

Setiap metode akan diuji dengan simulasi serangan untuk mengevaluasi tingkat kerentanannya.

Tools yang digunakan:

Mengamankan Secret Key

Dalam eksperimen ini, berbagai teknik diterapkan untuk meningkatkan keamanan penyimpanan secret key, sehingga lebih sulit untuk diekstraksi oleh attacker.

Teknik
Metode
Deskripsi

Obfuscation

  • menyamarkan secret key agar sulit ditemukan dalam source code

  • Mengurangi risiko eksploitasi melalui static analysis atau decompilation

  • Sebagai lapisan perlindungan awal sebelum metode keamanan lainnya

Jetpack Security Library

EncryptedSharedPreferences

  • Mengamankan data yang disimpan di SharedPreferences dengan enkripsi.

  • Menggunakan master key dengan algoritma AES-256 untuk melindungi data

EncryptedFile

  • Memungkinkan penyimpanan file dalam format terenkripsi

  • Mengurangi risiko pengambilan secret key dari file yang disimpan di perangkat

Native Library (C++)

  • Menyimpan secret key di dalam native code menggunakan C++

  • Lebih sulit didekompilasi dibandingkan kode Java atau Kotlin

  • Memerlukan teknik khusus seperti hooking atau debugging tingkat lanjut untuk diekstraksi

Encode dengan Base64

  • Tidak cukup kuat sebagai metode utama, tetapi berguna jika dikombinasikan dengan teknik lain

  • Menambahkan lapisan enkripsi tambahan untuk meningkatkan keamanan

Dengan mengkombinasikan berbagai teknik ini, keamanan secret key dalam aplikasi setidaknya diperkuat, mengurangi risiko serangan berbasis reverse engineering dan eksploitasi runtime.

Metode Serangan

Attacker menggunakan berbagai teknik untuk mengekstrak secret key dari aplikasi, yang mencakup:

  1. Static Analysis

Static analysis dilakukan dengan mengekstrak dan meneliti APK tanpa menjalankan aplikasi. Langkah-langkah yang dilakukan meliputi:

  • Dekompilasi APK menggunakan JADX untuk membaca kode sumber dan mencari kemungkinan penyimpanan secret key.

  • Pencarian String dalam kode dan resource file untuk menemukan pola yang mengarah ke secret key.

  • Analisis Smali Code, terutama jika kode dikompilasi dan mengalami obfuscation ringan.

  1. Dynamic Analysis & Hooking dengan Frida

Dynamic analysis dilakukan dengan menjalankan aplikasi dalam lingkungan emulator atau perangkat uji untuk memantau perilaku runtime. Untuk mengakses secret key secara runtime, attacker menggunakan Frida, sebuah dynamic instrumentation tool, dengan langkah-langkah berikut:

  • Memasang Frida pada emulator atau perangkat fisik untuk memungkinkan interaksi dengan aplikasi saat runtime.

  • Menulis dan menginjeksikan Frida Script untuk mencari fungsi yang menangani secret key, seperti metode yang mengembalikan kunci atau melakukan enkripsi/dekripsi.

  • Mengambil output secret key langsung dari memori aplikasi sebelum digunakan.

Pengujian

Eksperimen #1 Level Easy

Salah satu pendekatan umum yang biasa dilakukan yaitu menyimpan Secret Key di file .properties. Metode ini relatif aman karena kemungkinan developer secara tidak sengaja pushing file tersebut ke public repository lebih kecil, asalkan file tersebut telah didaftarkan dengan benar di file .gitignore.

Beberapa online sources yang merekomendasikan untuk menempatkan Secret Key di gradle.properties atau local.properties khusus untuk Secret Key seperti— apikey.properties–agar lebih terorganisir.

Selanjutnya, kita perlu memuat secret key pada apikey.properties dan membuatnya dapat diakses dalam kode kita. Kita dapat melakukannya dengan menambahkan pada class BuildConfig, yang secara otomatis generated oleh Gradle selama proses build.

Untuk mengaktifkan BuildConfig, tambahkan snippet berikut pada file app/build.gradle:

Setelah secret key di define di BuildConfig, kita dapat akses dengan cara:

Dengan cara ini, secret key tetap tersembunyi ketika kita perlu membuat source code kita public, tetapi dapat diakses dalam project.

Cracking Eksperimen #1 Level Easy

Link APK : rndforge-crackme1.apk

https://drive.google.com/file/d/1ImUPycXZU-abikuaunlDrQBDjFb867zU/view?usp=sharing

Static Analysis

Untuk melakukan static analysis dibutuhkan aplikasi Jadx-gui untuk melakukan decompiling dan menganalisis code nya. Pada eksperimen kali ini secret key nya terdapat pada function MainActivity.viewOnclickListener, seperti pada gambar di bawah.

Dari percobaan berikut didapati bahwa secret key sangat mudah di temukan oleh attacker hanya dengan melakukan static analysis.

Eksperimen #2 Level Medium

Pada eksperimen berikutnya, kita akan menyimpan secret key didalam native library dengan membuat Android Native Library module.

Selanjutnya, buat metode yang returns secret key dan diimplementasikan di native library.

Kemudian, Simpan secret key di dalam native library.

Langkah berikutnya adalah mengakses secret key ini di dalam kode Kotlin. Untuk menambahkan security layer tambahan, kita juga menyimpannya menggunakan EncryptedSharedPreferences dari Jetpack Security Library.

Dengan cara ini, kita berharap secret key tidak mudah ditemukan. Terakhir, kita hanya perlu memverifikasi Secret Key dengan yang telah disimpan di Shared Preferences.

Cracking Eksperimen #2 Level Medium

Link APK : rndforge-crackme2.apk

https://drive.google.com/file/d/1_UiJYT-GDxMOfjD14mHr08qQu24-Ej7M/view?usp=sharing

Dynamic Analysis & Hook Function dengan Frida

Pada eksperimen ke-2 kali ini, akan melakukan hook pada function yang ada pada aplikasinya. Pada kasus ini frida melakukan hook pada java class untuk cryptography “javax.crypto.Cipher” yang dimana ini adalah java class standard untuk melakukan enkripsi dan dekripsi. Jadi setiap aplikasi android yg melakukan proses enkripsi dan dekripsi function nya akan termonitor dan di dump value yg terkait key dari enkripsinya.

Frida script (https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security/blob/master/custom_scripts/Android/tracer_cipher.js)

Eksperimen ini bertujuan untuk menyimpan secret key dengan lebih aman, menggunakan kombinasi Native Library dan EncryptedSharedPreferences. Dalam metode ini, secret key tidak lagi disimpan secara langsung di dalam source code aplikasi, melainkan disimpan dalam Native Library yang lebih sulit untuk diakses melalui static analysis. Selain itu, EncryptedSharedPreferences dari Jetpack Security Library digunakan untuk menambahkan lapisan keamanan tambahan.

Meskipun metode ini meningkatkan keamanan, Frida tetap dapat digunakan untuk mengekstrak secret key selama proses runtime. Frida script secara spesifik menargetkan kelas javax.crypto.Cipher, yang bertanggung jawab untuk melakukan enkripsi dan dekripsi dalam aplikasi Android.

Eksperimen #3 Level Hard

Pada eksperimen berikutnya, kita tidak hanya menyimpan secret key di Native Library, tetapi juga meng-encode menggunakan Base64 sebagai lapisan tambahan sebanyak dua kali.

Selain itu, kita menggunakan pendekatan berbeda dengan menyimpan secret key dalam EncryptedFile dari Jetpack Security Library.

Sebenarnya, Anda bisa memilih skema enkripsi lain, tetapi dalam eksperimen ini, kita menggunakan AES256_GCM_HKDF_4KB. Skema ini termasuk sebagai salah satu opsi paling umum digunakan.

Selanjutnya, kita melakukan verifikasi secret key menggunakan nilai telah disimpan pada EncryptedFile, dan proses verifikasi juga dilakukan dalam native library.

Karena kita mengenkripsi secret key dua kali, maka kita juga perlu mendeskripsinya dua kali juga untuk melakukan verifikasi.

Cracking Eksperimen #3 Level Hard

Link APK : rndforge-crackme3.apk (https://drive.google.com/file/d/1rUYayRwxm6CTyQByOHC71qo8Vl3r71dw/view?usp=sharing)

Static Analysis

Pada eksperimen ke-3 kali ini, bisa dilihat pada pada proses awal melakukan storing secret key pada local storage yang kemudian nanti akan dipanggil kembali pada saat proses verifikasi.

Pada snippet code di bawah, bisa di lihat proses untuk melakukan validasi.

Secara detail proses validasi terdapat pada method m408z, untuk melakukan verifikasi file secret key yang sudah disimpan pada storage akan dipanggil kembali kemudian akan di compare dengan inputan dari user. Proses untuk melakukan verifikasi ada pada Native Library.

Dynamic Analysis & Hook Function dengan Frida

Secara behaviour bisa diamati bahwa asumsi dari static analysis terbukti pada proses berikut. Bisa di lihat proses yang terjadi pada storage, terdapat WRITE file dan READ file.

Jika diamati lebih detail pada proses mekanisme enkripsinya, bisa kita lihat bahwa terdapat key dalam bentuk HEX beserta algoritma yang digunakan AES/GCM/NoPadding.

Step berikutnya adalah mencoba untuk melihat isi dari file android_forge yang menjadi secret key, namun file tersebut sepertinya terenkripsi.

Berikut adalah hasil decompile dari NativeLib function, terdapat 2 function secret key dan verify, function ini digunakan untuk generate secret key yang ditulis pada storage, dan function verify untuk melakukan verifikasi.

Step berikutnya adalah melakukan Hook pada function m408z dan NativeLib untuk melihat data yang menjadi inputan pada function tersebut. Berikut adalah frida code untuk melakukan hook pada NativeLib Verify.

Dan hasil nya akan terlihat seperti berikut pada terminal.

Pada akhirnya, eksperimen ke-3 kali ini, secret key berhasil ditemukan dengan cara melakukan Hook pada NativeLib function verify. Setelah melakukan hook pada function tersebut bisa terlihat value yang di parsing ke dalam method verify yaitu “YUdWb1pXaGxYM2xsYzE5MGFHbHpYMmx6WDJsMA==”, dengan cepat bisa diidentifikasi sebagai base64 encoding. Namun pada percobaan pertama kesulitan untuk melakukan decode pada secret key tersebut dikarenakan menggunakan double encoding.

Beberapa kasus juga memungkinkan untuk melakukan perubahan flow program yang sedang berjalan, dalam kasus ini, attacker mampu untuk mengubah flow validasi secret key dengan memasukkan key yang salah, namun bisa mendapatkan validasi benar.

Kesimpulan

Eksperimen dilakukan dengan menguji tiga metode penyimpanan secret key, masing-masing memiliki tingkat keamanan yang berbeda. Metode pertama, yang dikategorikan sebagai Level Easy, menyimpan secret key dalam file properties. Pendekatan ini memang cukup sederhana tetapi masih rentan terhadap static analysis. Dengan menggunakan tools seperti JADX decompiler, attacker dapat dengan mudah menemukan Secret Key yang tersembunyi dalam source code. Hal ini menunjukkan bahwa penyimpanan secret key dalam file properties bukanlah metode yang aman untuk melindungi informasi sensitif.

Pada eksperimen berikutnya, pendekatan yang lebih aman diterapkan dengan menggunakan kombinasi Native Library dan EncryptedSharedPreferences, yang dikategorikan sebagai Level Medium. Dengan cara ini, secret key tidak lagi langsung disimpan dalam source code, melainkan diletakkan dalam Native Library, sehingga lebih sulit untuk ditemukan melalui static analysis. Selain itu, EncryptedSharedPreferences dari Jetpack Security Library digunakan untuk menambah lapisan keamanan tambahan. Namun, meskipun lebih sulit untuk diakses dibandingkan metode sebelumnya, metode ini secret key tetap dapat diketahui melalui dynamic analysis dan dengan menggunakan Frida. Dengan melakukan hooking pada java class javax.crypto.Cipher, attacker dapat memonitor semua proses enkripsi dan dekripsi yang dilakukan oleh aplikasi, sehingga memungkinkan mereka untuk mengekstrak secret key saat runtime.

Metode terakhir, yang dikategorikan sebagai Level Hard, menggunakan pendekatan yang lebih kompleks dengan mengkombinasikan Native Library, Base64 Encoding, dan EncryptedFile. Dalam eksperimen ini, secret key tidak hanya disimpan dalam Native Library, tetapi juga di-encode menggunakan Base64 sebanyak dua kali untuk menambah lapisan perlindungan. Selain itu, secret key disimpan dalam EncryptedFile dari Jetpack Security Library, yang menjadikannya lebih sulit untuk diakses. Meskipun metode ini menawarkan tingkat keamanan yang lebih tinggi dibandingkan dua metode sebelumnya, eksperimen menunjukkan bahwa secret key tetap dapat diekstrak dengan teknik yang lebih canggih. Dengan melakukan hooking pada fungsi verifikasi dalam Native Library, attacker dapat menemukan secret key ketika akan melakukan proses verifikasi, karena pada saat melakukan verifikasi, secret key berbentuk plain text yang hanya di-encode dengan base64. Hal ini membuktikan bahwa meskipun metode ini jauh lebih sulit untuk diretas, tetap ada celah bagi attacker yang memiliki pemahaman mendalam tentang sistem keamanan Android.

Hasil eksperimen ini memberikan wawasan berharga mengenai efektivitas berbagai metode dalam menyimpan secret key. Kesimpulan utama yang dapat diambil adalah bahwa tidak ada metode yang sepenuhnya aman untuk menyimpan secret key dalam aplikasi Android. Setiap metode yang digunakan, baik yang sederhana maupun yang kompleks, masih memiliki potensi untuk dieksploitasi jika attacker memiliki alat dan teknik yang tepat. Oleh karena itu, para developer harus memahami bahwa keamanan aplikasi bukan hanya tentang memilih satu metode terbaik, melainkan tentang menerapkan multiple layers of security untuk mengurangi risiko serangan.

Referensi

Tentang Penulis

Lalu Raynaldi Pratama Putra Security Researcher at PT ITSEC Asia Tbk

linkedin.com/in/raynaldilalu

As a researcher, I’m constantly discovering, learning, and pushing boundaries.

Meyta Zenis Taliti

Product Researcher at PT ITSEC Asia Tbk linkedin.com/in/meyta-taliti

Experienced Android Engineer, now exploring Cybersecurity as a Product Researcher

Last updated