Autentikasi biometrik standar pada React Native sering kali diimplementasikan secara naif: JavaScript runtime memanggil API biometrik natif, menunggu respons penyelesaian, dan memeriksa nilai boolean success === true. Pendekatan ini rentan dieksploitasi.
Penyerang bermodalkan perangkat yang telah di-root atau di-jailbreak dapat dengan mudah memotong alur logika ini menggunakan Frida, Objection, atau Xposed framework. Cukup dengan menimpa nilai balik metode natif (misalnya BiometricPrompt.AuthenticationCallback.onAuthenticationSucceeded pada Android atau LAContext.evaluatePolicy pada iOS), seluruh sistem proteksi aplikasi dapat ditembus tanpa menyentuh sensor sidik jari sama sekali.
Vulnerabilitas Logika Boolean dan Anatomi Runtime Hooking
Saat aplikasi hanya mengevaluasi status keberhasilan secara lokal di sisi klien, batasan keamanan (trust boundary) berada sepenuhnya di lingkungan yang dapat dikendalikan oleh penyerang. Script Frida berikut mengilustrasikan betapa mudahnya memotong logika autentikasi lokal standar:
// Frida script untuk bypass verifikasi boolean lokal
Java.perform(() => {
const FingerprintManager = Java.use('android.hardware.fingerprint.FingerprintManager');
FingerprintManager.authenticate.overload(
'android.hardware.fingerprint.FingerprintManager$CryptoObject',
'android.os.CancellationSignal',
'int',
'android.hardware.fingerprint.FingerprintManager$AuthenticationCallback',
'android.os.Handler'
).implementation = function (crypto, cancel, flags, callback, handler) {
// Bypass: langsung panggil callback onAuthenticationSucceeded tanpa proses sensor
callback.onAuthenticationSucceeded(null);
};
});Ketika hook dijalankan, library React Native akan menerima sinyal berhasil dan meneruskan status sukses ke layer JavaScript. Aplikasi kemudian menganggap pengguna telah terautentikasi dan mengeksekusi aksi sensitif, seperti mengambil token sesi atau memicu transfer dana.
Solusi: Asymmetric Cryptographic Challenge-Response
Solusi standar industri untuk mencegah bypass logika lokal adalah mengikat keberhasilan biometrik dengan operasi kriptografi asimetris di dalam perangkat keras terisolasi (Android KeyStore / iOS Secure Enclave). Kunci privat (private key) di-generate di dalam modul keamanan perangkat keras dengan flag khusus: kunci hanya dapat digunakan untuk melakukan proses signing jika sensor biometrik berhasil diverifikasi secara fisik.
Alur Kerja Protokol:
- Registrasi: Klien men-generate pasangan kunci asimetris (misal ECDSA P-256) di Secure Enclave / KeyStore. Kunci privat tidak pernah keluar dari modul hardware. Kunci publik dikirim dan disimpan di database backend yang diasosiasikan dengan akun pengguna.
- Challenge Request: Saat pengguna hendak melakukan aksi sensitif atau login, klien meminta nonce (challenge acak) dari server.
- Hardware Signing: Klien menandatangani payload
nonce + timestamp + userIdmenggunakan kunci privat. Operasi ini secara otomatis memicu prompt biometrik sistem. Jika pengguna gagal atau di-bypass di layer software, kunci privat tetap terkunci di level hardware dan penandatanganan payload gagal. - Verifikasi Server: Klien mengirimkan signature ke server. Server memverifikasi signature menggunakan kunci publik terdaftar dan memastikan nonce belum kedaluwarsa serta belum pernah digunakan (mencegah replay attack).
Implementasi Native Klien: React Native
Untuk menghindari manipulasi memori pada library JavaScript murni, gunakan implementasi yang mengekspos API penandatanganan hardware natif, seperti react-native-biometrics atau native module kustom yang mengonfigurasi flags hardware secara ketat.
1. Inisialisasi Pasangan Kunci dengan Hardware-Binding
import ReactNativeBiometrics, { BiometryTypes } from 'react-native-biometrics';
const rnBiometrics = new ReactNativeBiometrics();
async function registerBiometricKey(): Promise<string | null> {
const { biometryType } = await rnBiometrics.isSensorAvailable();
if (!biometryType) {
throw new Error('Sensor biometrik tidak tersedia atau dinonaktifkan.');
}
// Generate EC P-256 Keypair di Secure Enclave / Android KeyStore
const { publicKey } = await rnBiometrics.createKeys();
return publicKey;
}2. Menandatangani Challenge dari Server
async function authenticateWithBiometrics(challengeNonce: string) {
const payload = `challenge:${challengeNonce}`;
const { success, signature } = await rnBiometrics.createSignature({
promptMessage: 'Konfirmasi otorisasi biometrik',
payload: payload,
cancelButtonText: 'Batal',
});
if (!success || !signature) {
throw new Error('Proses otentikasi biometrik gagal atau dibatalkan.');
}
return signature;
}Konfigurasi Tingkat Natif: Menangkal Serangan Pendaftaran Biometrik Baru
Salah satu celah kritis pada perangkat terkompromi adalah skenario di mana penyerang menambahkan sidik jari mereka sendiri ke pengaturan OS target. Jika aplikasi tidak dikonfigurasi dengan benar, sidik jari penyerang yang baru dapat dipakai untuk membuka kunci privat yang ada.
Android: setUserAuthenticationRequired dan setInvalidatedByBiometricEnrollment
Pada sisi native Android, pastikan KeyGenParameterSpec dikonfigurasi agar secara otomatis membatalkan validitas kunci jika ada perubahan pada template biometrik perangkat:
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
KEY_ALIAS,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(true)
// Kunci otomatis rusak/invalid jika ada pendaftaran biometrik baru
.setInvalidatedByBiometricEnrollment(true);iOS: kSecAccessControlBiometryCurrentSet
Pada iOS, flag kSecAccessControlBiometryAny memungkinkan biometrik yang baru didaftarkan tetap dapat mengakses kunci. Ganti parameter tersebut dengan kSecAccessControlBiometryCurrentSet.
SecAccessControlCreateWithFlags(
kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.biometryCurrentSet, // Invalid jika ada sidik jari / wajah baru didaftarkan
&error
);Catatan: Jika pengguna menambahkan jari baru ke perangkat mereka, kunci privat yang dilindungi oleh flag ini akan terhapus atau dibatalkan secara permanen oleh hardware. Aplikasi harus menangani exception ini dan mengarahkan pengguna untuk mendaftar ulang dengan kredensial utama (seperti password atau 2FA OTP).
Verifikasi Sisi Server (Backend)
Server bertindak sebagai pemegang otoritas tunggal. Jangan pernah mempercayai klien tanpa memvalidasi signature secara kriptografis terhadap payload challenge yang diterbitkan.
import crypto from 'crypto';
interface VerifyRequest {
publicKeyBase64: string;
signatureBase64: string;
nonce: string;
}
export function verifyBiometricChallenge({
publicKeyBase64,
signatureBase64,
nonce,
}: VerifyRequest): boolean {
const payload = Buffer.from(`challenge:${nonce}`, 'utf8');
const signature = Buffer.from(signatureBase64, 'base64');
// Rekonstruksi public key dalam format PEM atau DER
const publicKey = crypto.createPublicKey({
key: Buffer.from(publicKeyBase64, 'base64'),
format: 'der',
type: 'spki',
});
const verifier = crypto.createVerify('SHA256');
verifier.update(payload);
verifier.end();
// Verifikasi signature ECDSA
return verifier.verify(publicKey, signature);
}Menangani Siklus Hidup dan Error Boundary Hardware
Implementasi kriptografi tingkat rendah membutuhkan penanganan error yang komprehensif pada lapisan presentasi React Native:
KeyPermanentlyInvalidatedException: Terjadi saat biometrik baru didaftarkan di perangkat. Tangkap error ini, bersihkan kunci lokal viadeleteKeys(), tandai kunci di server sebagai non-aktif, lalu paksa pengguna login ulang via kredensial fallback.- Hardware Lockout: Kegagalan verifikasi sensor berulang kali akan memicu
BIOMETRIC_LOCKED_OUTsecara natif di KeyStore. Matikan tombol biometrik di UI klien untuk sementara waktu dan tawarkan input PIN/Password aplikasi. - Hardware Unavailability: Kasus di mana hardware enkripsi sedang sibuk atau OS berada di status Direct Boot sebelum enkripsi disk dibuka. Selalu sediakan jalur autentikasi alternatif berbasis server.
Dengan memindahkan validasi dari status boolean lokal ke pembuktian kepemilikan kunci melalui tanda tangan kriptografis di server, teknik runtime hook Frida tidak lagi berguna karena attacker tidak dapat memalsukan signature tanpa mengekstrak private key dari hardware terisolasi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!