Langsung ke konten utama
Mobile Keamanan

Praktik Terbaik Penyimpanan Token untuk Aplikasi Mobile (2026)

Praktik terbaik penyimpanan token: akses token di memori, refresh token di Keychain atau Keystore, rotasi, dan beralih dari EncryptedSharedPreferences.

Cara menyimpan access dan refresh token secara aman di mobile dengan Keychain dan Keystore

Cara paling aman untuk menyimpan access token di aplikasi modern adalah tidak mempersistkannya: simpan access token berumur pendek di memori selama sesi dan buat yang baru setiap kali aplikasi dibuka dari refresh token yang disimpan di penyimpanan terenkripsi berbasis platform. Persist hanya refresh token di iOS di Keychain dan di Android dengan Android Keystore (software, TEE, atau StrongBox tergantung perangkat) plus Jetpack DataStore + Tink. EncryptedSharedPreferences sudah deprecated di androidx.security.crypto; rencanakan migrasi sekarang. Untuk Capacitor aplikasi, kombinasikan keamanan transport (HTTPS, alat dan plugin SSL pinning) dengan plugin penyimpanan berbasis native dan @capgo/capacitor-native-biometric alih-alih menduplikasi crypto di JavaScript.

Cara Kami Memilih Pola Storage Ini

Setiap rekomendasi di sini melewati empat filter. Pertama, penyimpanan terlindungi platform: secret harus disimpan di Keychain atau Keystore, atau dienkripsi dengan key yang tersimpan di sana. Utamakan hardware-backed isolation jika konfigurasi perangkat dan key memang mendukungnya (misalnya key yang didukung StrongBox atau Secure Enclave). Kedua, jalur migrasi resmi. Jika Google atau Apple sudah deprecated pendekatan tersebut, kami tidak merekomendasikannya untuk code baru. Ketiga, kompatibilitas Capacitor: pola ini harus bisa dipakai dari batas plugin tanpa mengekspos raw key ke JavaScript. Keempat, revocability: credential yang bocor harus bisa diinvalidasi di sisi server.

Filter terakhir itulah alasan mengapa refresh token rotation dibahas di seluruh artikel ini. Chainalysis melaporkan lebih dari $305 juta dicuri dari DMM Bitcoin di Jepang setelah kompromi private key pada 2024 (laporan kejahatan Chainalysis 2024). Token auth mobile gagal dengan cara yang sama: bearer token berumur panjang dalam plaintext storage adalah undangan terbuka bagi penyerang. Kami tidak akan merekomendasikan arsitektur apa pun yang menyimpan kredensial non-rotating secara permanen.

Prinsip yang berlaku di setiap platform

Tabel di bawah ini merangkumnya menjadi snapshot; logika dasarnya adalah pemisahan access/refresh token. Sebuah access token berumur pendek, hitungan menit bukan hari, dan itulah yang disebut 'present' oleh API Anda. Karena blast radius-nya kecil dan cepat kedaluwarsa, token ini hanya disimpan di memori dan dibuat ulang setiap kali aplikasi dijalankan. refresh token adalah rahasia tahan lama yang memungkinkan Anda menerbitkan access token baru, sehingga hanya token ini yang layak disimpan di storage terenkripsi persisten yang didukung hardware. Masa berlaku yang berbeda menuntut tempat penyimpanan berbeda; menyimpan keduanya dengan cara yang sama adalah awal mula sebagian besar kebocoran.

Urutan lengkap saat runtime seperti ini: aplikasi berjalan tanpa access token, memanggil auth server dengan refresh token yang tersimpan, menerima access token baru di memori, lalu menghapus refresh token lama karena server merotasinya setiap kali dipakai. Jika server sampai melihat refresh token yang sudah terpakai dikirim lagi, server menganggapnya sebagai bukti pencurian dan mencabut seluruh token family. Saat logout, client menghapus local storage dan server mencabut grant tersebut. Menghapus data secara lokal tanpa pencabutan di server hanyalah harapan, bukan keamanan.

Praktik Mengapa ini penting
Access token berumur pendek Membatasi dampak jika token bocor
Rotasi refresh token Membatalkan refresh token yang dicuri setelah penggunaan sah
Hanya HTTPS Mencegah intersepsi jaringan sederhana
Certificate pinning (jika diperlukan) Mengurangi risiko dari root yang diterbitkan secara tidak tepat atau kustom; lihat panduan certificate pinning OWASP
Tanpa token di logs, URL, atau analytics Token di tools observability berujung pada kebocoran data
Pencabutan token saat logout Invalidasi di sisi server lebih baik daripada berharap client menghapus data

@capgo/capacitor-ssl-pinning Anda dapat mem-pin TLS untuk Capacitor HTTP di iOS dan Android jika membutuhkan kontrol transport yang lebih ketat. Untuk gambaran lebih luas tentang penguatan transport, lihat alat dan plugin implementasi SSL pinning.

Android: Keystore dan DataStore (bukan EncryptedSharedPreferences)

Google telah mendepresiasi androidx.security.crypto helper, termasuk EncryptedSharedPreferences dan MasterKey. Ringkasan package memberi tahu developer untuk menggunakan KeyGenerator dengan provider AndroidKeyStore untuk material key baru.

Gunakan satu pipeline berbasis Tink secara end-to-end:

  1. Buat Tink keyset dengan AndroidKeysetManager, menyimpan master key di Android Keystore melalui android-keystore:// URI (lihat datastore-tink catatan rilis). Panggil isUsingKeystore() pada manager dan terapkan fail closed saat mengembalikan false. Jika tidak, Tink dapat menyimpan keyset dalam bentuk cleartext.
  2. Dapatkan Aead primitive dari keyset tersebut.
  3. Tambah androidx.datastore:datastore-tink (DataStore 1.3.0 menyertakan artifact; 1.2.x tidak), bungkus Serializer dengan AeadSerializer, dan teruskan ke DataStore. Saat beberapa store berbagi satu Aead key, berikan setiap store associatedDatayang unik, seperti nilai stabil dari nama filenya.

Google mendokumentasikan ini sebagai jalur pengganti yang didukung untuk androidx.security.crypto helpers. Jangan mencampur JCA standalone SecretKey dengan AeadSerializer; serializer mengharapkan Tink Aead instance.

Opsi Keystore yang perlu diketahui

  • setIsStrongBoxBacked(true) saat FEATURE_STRONGBOX_KEYSTORE tersedia untuk isolasi key yang lebih kuat.
  • Autentikasi pengguna binding (setUserAuthenticationRequired) saat token hanya boleh diakses setelah biometrik atau kredensial perangkat.
  • Hindari Auto Backup untuk file yang menyimpan keyset atau ciphertext kecuali Anda memahami perilaku restore; dokumentasi EncryptedSharedPreferences Google memperingatkan bahwa backup dapat memulihkan ciphertext tanpa kunci.

Modul Kotlin atau Java native di Capacitor harus menerapkan pola ini di dalam plugin; JavaScript hanya boleh menerima opaque handle atau session state, bukan raw keys.

iOS: Keychain dan Secure Enclave

Panduan Keychain tetap menjadi tempat yang tepat untuk token di iOS. Item dienkripsi dan dilindungi oleh sistem. Gunakan konstanta accessibility dengan cakupan sempit dan Kontrol Akses saat Anda membutuhkan Face ID, Touch ID, atau proteksi passcode.

Pilihan accessibility adalah keputusan krusial, bukan default yang asal disalin. Pilih kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly saat token harus bisa dipakai oleh proses background, seperti refresh yang dipicu push atau background fetch, tapi tidak boleh ikut pindah ke perangkat baru lewat backup. Pilih kSecAttrAccessibleWhenUnlockedThisDeviceOnly untuk penggunaan token hanya di foreground, di mana jendela yang lebih ketat sepadan dengan batasannya. Dalam kedua kasus, aktifkan kSecUseDataProtectionKeychain pada target modern agar Anda mendapatkan Keychain data-protection, bukan versi file-based yang lama.

CryptoKit membantu jika Anda mengenkripsi payload sendiri, tetapi untuk bearer token standar ala OAuth, menyimpan string token langsung di Keychain dengan accessibility yang tepat biasanya sudah cukup. Kunci berbasis Secure Enclave (kunci P-256 yang dibuat dengan SecureEnclave di CryptoKit) hanya menguntungkan jika kuncinya sendiri tidak boleh keluar dari hardware aman, misalnya untuk operasi penandatanganan atau atestasi perangkat. Mereka tidak bisa menyimpan string token untuk Anda; mereka melindungi envelope key Anda sendiri. Jika Anda tidak melakukan rotasi envelope dan mengelola siklus hidupnya, penyimpanan Keychain biasa lebih sederhana dan sama amannya. Enkripsi tambahan di lapisan aplikasi hanya membantu jika Anda juga melakukan rotasi kunci dan mengelola envelope dengan hati-hati.

milik Capacitor @capacitor/preferences menulis ke UserDefaults, yang merupakan tidak penyimpanan rahasia. Jangan simpan token di sana.

Capacitor: opsi penyimpanan aman di org Cap-go

Cap-go melakukan tidak mengirimkan paket bernama “secure storage,” tetapi dua plugin mencakup kebutuhan umum Capacitor:

Plugin Terbaik untuk Backing native
@capgo/capacitor-native-biometric setData / getSecureData Rahasia kecil (session token, kunci API) iOS Keychain; enkripsi berbasis Android Keystore di SharedPreferences
@capgo/capacitor-data-storage-sqlite dengan opsi enkripsi Data lokal yang lebih besar atau terstruktur SQLite dengan SQLCipher opsional

Panduan panduan penyimpanan key-value membandingkan Preferences, SQLite stores, dan NativeBiometric.setData untuk secrets.

Membutuhkan @capgo/capacitor-native-biometric 8.6.0 atau lebih baru (cocokkan major version plugin dengan major version Capacitor Anda). Contoh dengan pembacaan yang dilindungi biometrik:

import {
  AccessControl,
  NativeBiometric,
} from '@capgo/capacitor-native-biometric';

const TOKEN_KEY = 'auth.refresh_token';

export async function saveRefreshToken(token: string) {
  await NativeBiometric.setData({
    key: TOKEN_KEY,
    value: token,
    accessControl: AccessControl.BIOMETRY_CURRENT_SET,
  });
}

export async function loadRefreshToken(): Promise<string | null> {
  try {
    const { value } = await NativeBiometric.getSecureData({
      key: TOKEN_KEY,
      reason: 'Unlock your session',
      title: 'Authenticate',
    });
    return value ?? null;
  } catch {
    return null;
  }
}

getData hanya mengembalikan nilai yang disimpan tanpa accessControl. Untuk perlindungan biometrik, selalu pasangkan BIOMETRY_CURRENT_SET atau BIOMETRY_ANY dengan getSecureData.

Untuk web builds, jangan pernah menyimpan production token di localStorage. Gunakan model web session backend Anda sebagai gantinya.

Siklus hidup token di server dan klien

Ya, aplikasi mobile sebaiknya menyimpan refresh token. Alternatifnya adalah memaksa pengguna melakukan autentikasi ulang setiap kali aplikasi dibuka, yang justru lebih buruk daripada keamanan sungguhan. Nuansanya ada di di mana dan bagaimana: simpan hanya refresh token, hanya di penyimpanan yang didukung Keychain atau Keystore, dan hanya dengan rotasi serta pencabutan di sisi server.

Cara mengelola dan merotasi refresh token dengan aman di aplikasi mobile

Rotasi adalah yang membuat penyimpanan token aman. Keluarkan refresh token sebagai sekali pakai credentials: setiap redemption mengembalikan refresh token baru dan membatalkan yang lama. Server menyimpan durasi singkat deteksi penggunaan ulangyang singkat. Jika token yang seharusnya sudah digunakan muncul lagi, server menganggap family tersebut terkompromi dan mencabut seluruh rantai, memaksa login baru di semua perangkat yang membagikannya. Beri toleransi kecil (beberapa detik hingga satu menit) untuk request yang bersaing dan koneksi ulang offline, di mana klien yang sah mungkin menyajikan token lama sekali lagi sebelum mengetahui penggantian. Tanpa toleransi, pengguna dengan koneksi tidak stabil akan terkunci; jendela yang terlalu panjang memperluas permukaan serangan.

Lokasi penyimpanan setiap token mengikuti langsung dari masa berlakunya:

  • Masalah access token dengan TTL pendek (menit, bukan hari), dan simpan hanya di memori selama sesi tersebut.
  • Persist refresh token di penyimpanan terenkripsi yang didukung Keychain atau Keystore, dan rotasikan seperti di atas.
  • Saat ganti kata sandi, logout, atau perangkat hilang, cabut refresh token di sisi server. Menghapus data lokal di klien bukan pencabutan.
  • Pertimbangkan strategi token binding ringan (attestation kunci perangkat atau ID instance aplikasi) jika model ancaman Anda membutuhkannya.

Saat Anda merilis perbaikan keamanan untuk penanganan token di aplikasi Capacitor, Live updates Capgo dapat mengirimkan perubahan lapisan web yang memenuhi syarat dengan cepat jika Anda tetap mematuhi kebijakan toko. Perubahan penyimpanan native tetap memerlukan build toko. Capgo ringkasan keamanan merangkum bagaimana aplikasi produksi menggabungkan kontrol transport, penyimpanan, dan pembaruan.

Perbandingan opsi penyimpanan

Metode Keamanan fit Capacitor
Variabel JS in-memory Tinggi saat berjalan, hilang saat di-kill OK untuk access token hanya selama sesi
localStorage / Preferensi Rendah Hanya settings, bukan secrets
Keychain iOS / Keystore Android Tinggi Lewat native code atau plugin Capgo
DataStore + Tink (native Android) Tinggi Plugin Capacitor custom atau native auth SDK
Custom crypto di JS Variabel Hindari; key di JS bisa diekstrak

Catatan penting untuk baris terakhir: masalah crypto JavaScript bukan pada algoritma yang lemah, melainkan pada penempatannya. Key apa pun yang bisa dibaca runtime JS dapat dieksfiltrasi oleh apa pun lain yang ada di runtime tersebut, jadi "keamanan tinggi" secara struktural tidak bisa dicapai dari layer itu, apa pun library yang Anda pilih.

Checklist migrasi dari EncryptedSharedPreferences

  1. Inventarisasi key mana yang menyimpan secret dan mana yang config publik.
  2. Implementasikan DataStore + AeadSerializer dengan Tink keyset berbasis Keystore.
  3. Migrasi dengan SharedPreferencesMigration menggunakan producer yang membuka EncryptedSharedPreferences instance lama (bukan plain SharedPreferences), lalu hapus file lama setelah pembacaan berhasil.
  4. Rilis perubahan native melalui store; uji coba backup dan restore pada perangkat fisik.
  5. Hapus androidx.security.crypto dependencies saat tidak ada yang mereferensikannya.

FAQ

Bagaimana cara mengimplementasikan penyimpanan token yang aman?

Di iOS, tulis refresh token ke Keychain dengan atribut accessibility yang sesuai kebutuhan background refresh. Di Android, gunakan Tink keyset di Android Keystore dengan Jetpack DataStore dan AeadSerializer sebagai pengganti EncryptedSharedPreferences yang sudah deprecated. Simpan access token hanya di memori dan gunakan HTTPS. Tambahkan certificate pinning jika threat model Anda membutuhkannya.

Bagaimana cara mengelola dan melakukan rotasi refresh token secara aman di aplikasi mobile?

Simpan refresh token hanya di penyimpanan berbasis Keychain atau Keystore. Terbitkan refresh token sekali pakai agar setiap penukaran mengembalikan refresh token baru dan membatalkan yang lama. Pertahankan jendela deteksi penggunaan ulang yang singkat agar token yang di-replay mencabut seluruh family token, dengan grace period kecil untuk klien offline atau yang mengalami race condition.

Apakah penyimpanan aman untuk access token dan refresh token sama di iOS dan Android?

Pemisahannya sama di kedua platform: memory untuk access token berumur pendek, dan storage terenkripsi yang dilindungi platform untuk refresh token. API-nya berbeda (Keychain versus Keystore plus DataStore), tetapi keduanya harus menghindari WebView localStorage, UserDefaults, dan SharedPreferences polos untuk menyimpan rahasia.

Haruskah saya mengenkripsi token sebelum menyimpannya di Keychain?

Biasanya tidak perlu lapisan tambahan untuk bearer token standar jika aksesibilitas Keychain sesuai dengan model ancaman Anda. Tambahkan enkripsi envelope jika regulasi atau kebijakan rotasi key mengharuskannya.

Apakah SQLCipher di plugin Capacitor menggantikan Keystore?

SQLCipher melindungi file database, tetapi Anda tetap membutuhkan key yang kuat di Keystore atau Keychain untuk mendekripsi database. Perlakukan penanganan passphrase enkripsi sebagai bagian dari desain penyimpanan aman Anda.

Bisakah saya menyimpan token di Capacitor Preferences dengan obfuscation?

Obfuscation bukan enkripsi. Preferences dipetakan ke UserDefaults dan SharedPreferences tanpa perlindungan berbasis hardware.

Apakah aplikasi mobile harus menyimpan refresh token?

Ya, tetapi hanya di penyimpanan terenkripsi yang didukung Keychain atau Keystore, dipadukan dengan rotasi dan pencabutan di sisi server. Tidak menyimpan token berarti autentikasi ulang setiap kali aplikasi dibuka, yang justru mendorong pengguna untuk menuntut persyaratan login yang lebih lemah. Yang tidak pernah bisa diterima adalah refresh token disimpan di Preferences, localStorage, atau file plaintext mana pun.

Apa cara paling aman menyimpan access token di aplikasi modern?

Jangan simpan sama sekali. Simpan access token berumur pendek di memori selama sesi dan buat ulang dari refresh token setiap kali aplikasi diluncurkan. Simpan hanya refresh token di iOS Keychain atau penyimpanan terenkripsi berbasis Android Keystore, lalu biarkan rotasi dan revocation membatasi dampaknya jika perangkat sampai dikompromikan.

Lanjutkan dari Secure Token Storage: Best Practices for Mobile Developers

Jika Anda menggunakan Penyimpanan Token yang Aman: Best Practices untuk Mobile Developer untuk merencanakan keamanan dan kepatuhan, hubungkan dengan Enkripsi untuk detail implementasi pada Encryption, Kepatuhan untuk detail implementasi pada Compliance, Capgo Pemindai Keamanan untuk alur kerja produk di Capgo Security Scanner, Keamanan Capgo untuk alur kerja produk di Capgo Security, dan Capgo Pusat Kepercayaan untuk workflow produk di Capgo Trust Center.

Live updates untuk aplikasi Capacitor

Saat bug web-layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna mendapat update di background, sementara perubahan native tetap mengikuti jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.