Android Development dengan Kotlin: Amankan Data Sensitif dari Celah Insecure Data Storage
Sejak Google mengumumkan Kotlin-first pada 2019, bahasa ini menjadi standar pengembangan aplikasi Android modern. Sintaksnya ringkas, null-safety bawaan, dan coroutine memudahkan pengelolaan threading. Namun satu aspek sering terlewat: keamanan penyimpanan data. Artikel ini membahas celah Insecure Data Storage, cara mengeksploitasinya, dan mitigasinya dengan Kotlin.
Pendahuluan: Kenapa Keamanan Sering Diabaikan?
Fokus mayoritas developer ada pada fitur dan UI. Akibatnya, data sensitif seperti JWT atau kredensial pengguna disimpan begitu saja memakai SharedPreferences biasa. SharedPreferences menulis file XML di direktori privat aplikasi (/data/data/<package>/shared_prefs/). Direktori itu memang diisolasi oleh sandbox Android, tetapi bukan berarti aman sepenuhnya.
Pembahasan: Bagaimana Celah Ini Bekerja
Ada tiga jalur utama kebocoran data:
- Device rooted — akses root menembus sandbox dan membaca file XML langsung.
- ADB backup — jika
android:allowBackup="true"(nilai default), siapa pun dengan akses USB debugging bisa menarik data aplikasi. - Malware/forensik fisik — pada perangkat lama tanpa file-based encryption.
Contoh Implementasi yang Rentan
Perhatikan pola Kotlin berikut yang sangat umum ditemui:
class AuthRepository(context: Context) {
private val prefs = context
.getSharedPreferences("user_prefs", Context.MODE_PRIVATE)
fun saveToken(token: String) {
prefs.edit().putString("auth_token", token).apply()
}
fun getToken(): String? = prefs.getString("auth_token", null)
}
Kode ini berfungsi sempurna, tetapi token tersimpan sebagai plaintext. Isi file XML-nya:
<map>
<string name="auth_token">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...</string>
</map>
Analisis Keamanan: Demonstrasi Eksploitasi
Pada build yang debuggable atau perangkat yang sudah di-root, penyerang hanya butuh satu perintah:
adb shell run-as com.example.app cat \
/data/data/com.example.app/shared_prefs/user_prefs.xml
Perintah run-as menjalankan proses dengan UID aplikasi target, sehingga sandbox dilewati sepenuhnya. Alternatif lain: adb backup -f backup.ab com.example.app, yang menghasilkan arsip berisi seluruh data privat aplikasi. Setelah token didapat, penyerang bisa melakukan session hijacking — mengakses API atas nama korban tanpa password.
Cara Pencegahan yang Detail
1. Gunakan EncryptedSharedPreferences. Library Jetpack Security membungkus SharedPreferences dengan AES-256 dan menyimpan kunci di Android Keystore (hardware-backed pada perangkat yang mendukung):
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val securePrefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
securePrefs.edit().putString("auth_token", token).apply()
2. Matikan backup. Set android:allowBackup="false" dan android:fullBackupContent="false" pada tag <application> di AndroidManifest.xml.
3. Bersihkan log. Hapus Log.d() yang mencetak token. Gunakan R8/ProGuard dengan aturan -assumenosideeffects agar log terhapus otomatis di build rilis.
4. Aktifkan certificate pinning pada OkHttp supaya token tidak bocor lewat man-in-the-middle.
5. Rotasi token. Pakai access token berumur pendek plus refresh token.
6. Uji sendiri. Jalankan adb backup ke build rilis Anda — jika berhasil, konfigurasi Anda bocor.
Kesimpulan
Kotlin membuat pengembangan Android lebih produktif, tetapi produktivitas tanpa kesadaran keamanan berbahaya. SharedPreferences standar menyimpan data sebagai plaintext dan rentan pada perangkat rooted maupun lewat ADB backup. Solusinya berlapis: enkripsi dengan EncryptedSharedPreferences (atau Android Keystore langsung), nonaktifkan backup, bersihkan log, dan terapkan certificate pinning. Terapkan prinsip defense in depth — jangan bergantung pada satu mekanisme saja. Keamanan bukan fitur tambahan, melainkan bagian dari arsitektur sejak baris kode pertama.