生物識別變更偵測:Android 與 iOS 平台完整實作指南
前言
生物識別技術(指紋、Face ID、Touch ID)已成為現代行動應用的核心安全機制。然而,當使用者新增或刪除生物識別資料時,應用程式如何偵測這些變更以確保安全性?本文深入探討 Android 與 iOS 兩大平台的生物識別變更偵測實作方法,並提供完整程式碼範例。
為什麼需要偵測生物識別變更?
安全性考量
當使用者新增新的指紋或重設 Face ID 時,可能代表:
- 裝置擁有權轉移:手機轉賣或借給他人
- 安全性威脅:未授權人員嘗試新增自己的生物識別資料
- 資料存取風險:新增的生物識別資料可能用於存取敏感資料
實務應用場景
- 金融應用:銀行 App 需在生物識別變更時要求重新驗證
- 企業應用:MDM 系統需追蹤裝置安全狀態變更
- 健康應用:醫療 App 需確保敏感資料僅供授權使用者存取
Android 生物識別偵測實作
核心概念:BiometricManager
Android 提供 BiometricManager API 來檢查生物識別可用性。關鍵方法是 canAuthenticate(),返回裝置當前的生物識別狀態。
canAuthenticate() 返回值詳解
| 返回值 | 說明 | 處理建議 |
|---|---|---|
BIOMETRIC_SUCCESS |
生物識別功能可用且已設定 | 正常進行生物識別驗證 |
BIOMETRIC_ERROR_NONE_ENROLLED |
硬體支援但未設定生物識別資料 | 提示使用者前往設定頁面 |
BIOMETRIC_ERROR_HW_UNAVAILABLE |
硬體暫時無法使用 | 提供替代驗證方式(PIN/密碼) |
BIOMETRIC_ERROR_NO_HARDWARE |
裝置不支援生物識別 | 僅使用傳統驗證方式 |
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED |
需要安全性更新 | 提示使用者更新系統 |
實作範例:檢查生物識別可用性
import android.content.Context;
import androidx.biometric.BiometricManager;
import androidx.biometric.BiometricManager.Authenticators;
public class BiometricHelper {
public static BiometricStatus checkBiometricAvailability(Context context) {
BiometricManager biometricManager = BiometricManager.from(context);
int canAuthenticate = biometricManager.canAuthenticate(
Authenticators.BIOMETRIC_STRONG
);
switch (canAuthenticate) {
case BiometricManager.BIOMETRIC_SUCCESS:
return BiometricStatus.AVAILABLE;
case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
return BiometricStatus.NOT_ENROLLED;
case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
return BiometricStatus.TEMPORARILY_UNAVAILABLE;
case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
return BiometricStatus.NOT_SUPPORTED;
case BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
return BiometricStatus.SECURITY_UPDATE_REQUIRED;
default:
return BiometricStatus.UNKNOWN;
}
}
public enum BiometricStatus {
AVAILABLE,
NOT_ENROLLED,
TEMPORARILY_UNAVAILABLE,
NOT_SUPPORTED,
SECURITY_UPDATE_REQUIRED,
UNKNOWN
}
}
偵測生物識別變更策略
Android 並未提供直接的 API 來偵測生物識別資料變更。實務上需要使用以下策略:
方法一:定期檢查狀態(推薦)
public class BiometricChangeDetector {
private static final String PREFS_NAME = "biometric_prefs";
private static final String KEY_LAST_STATUS = "last_biometric_status";
public static boolean hasB
iometricChanged(Context context) {
SharedPreferences prefs = context.getSharedPreferences(
PREFS_NAME,
Context.MODE_PRIVATE
);
// 獲取當前狀態
BiometricStatus currentStatus = BiometricHelper.checkBiometricAvailability(context);
// 獲取上次記錄的狀態
String lastStatus = prefs.getString(KEY_LAST_STATUS, null);
// 首次檢查
if (lastStatus == null) {
saveCurrentStatus(context, currentStatus);
return false;
}
// 比較狀態是否改變
boolean changed = !currentStatus.name().equals(lastStatus);
if (changed) {
// 記錄變更並更新
Log.w("BiometricChange", "Biometric status changed from " +
lastStatus + " to " + currentStatus);
saveCurrentStatus(context, currentStatus);
}
return changed;
}
private static void saveCurrentStatus(Context context, BiometricStatus status) {
SharedPreferences prefs = context.getSharedPreferences(
PREFS_NAME,
Context.MODE_PRIVATE
);
prefs.edit()
.putString(KEY_LAST_STATUS, status.name())
.apply();
}
}
方法二:結合 Keystore 驗證
// 使用 Android Keystore 建立需要生物識別的金鑰
// 當生物識別資料變更時,金鑰將失效
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import javax.crypto.KeyGenerator;
import java.security.KeyStore;
public class KeystoreB
iometricDetector {
private static final String KEY_NAME = "biometric_key";
public static void createBiometricKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
);
keyGenerator.init(
new KeyGenParameterSpec.Builder(
KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true) // 關鍵設定
.build()
);
keyGenerator.generateKey();
}
public static boolean isBiometricKeyValid() {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
return keyStore.containsAlias(KEY_NAME);
} catch (Exception e) {
return false;
}
}
}
iOS 生物識別偵測實作
核心概念:evaluatedPolicyDomainState
iOS 的 LocalAuthentication 框架提供 evaluatedPolicyDomainState 屬性,用於偵測 Touch ID 或 Face ID 設定的變更。這個屬性返回一個 Data 物件,當生物識別資料變更時,這個值會改變。
實作範例:偵測生物識別變更
import LocalAuthentication
class BiometricChangeDetector {
private static let kBiometricStateKey = "biometric_domain_state"
// 檢查生物識別是否可用
static func canUseBiometric() -> Bool {
let context = LAContext()
var error: NSError?
return context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
)
}
// 獲取當前生物識別狀態
static func getCurrentBiometricState() -> Data? {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
) else {
return nil
}
return context.evaluatedPolicyDomainState
}
// 檢查生物識別是否已變更
static func hasBiometricChanged() -> Bool {
guard let currentState = getCurrentBiometricState() else {
// 生物識別不可用或未設定
return false
}
// 獲取上次儲存的狀態
guard let savedState = UserDefaults.standard.data(
forKey: kBiometricStateKey
) else {
// 首次檢查,儲存當前狀態
saveBiometricState(currentState)
return false
}
// 比較狀態是否變更
if currentState != savedState {
print("⚠️ Biometric configuration has changed!")
saveBiometricState(currentState)
return true
}
return false
}
// 儲存生物識別狀態
private static func saveBiometricState(_ state: Data) {
UserDefaults.standard.set(state, forKey: kBiometricStateKey)
}
// 清除儲存的狀態(使用者登出時)
static func clearBiometricState() {
UserDefaults.standard.removeObject(forKey: kBiometricStateKey)
}
}
實際應用範例
// 在 App 啟動時檢查生物識別變更
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidBecomeActive(_ application: UIApplication) {
checkBiometricSecurity()
}
private func checkBiometricSecurity() {
if BiometricChangeDetector.hasBiometricChanged() {
// 生物識別已變更,執行安全措施
handleBiometricChange()
}
}
private func handleBiometricChange() {
// 1. 記錄安全事件
SecurityLogger.log("Biometric configuration changed")
// 2. 清除敏感資料快取
clearSensitiveDataCache()
// 3. 要求使用者重新驗證
presentReauthenticationScreen()
// 4. 可選:通知後端伺服器
notifyServerBiometricChanged()
}
private func clearSensitiveDataCache() {
// 清除本地快取的敏感資料
KeychainHelper.clearAll()
UserDefaults.standard.removeObject(forKey: "cached_token")
}
private func presentReauthenticationScreen() {
// 顯示重新驗證畫面
let alert = UIAlertController(
title: "安全性變更偵測",
message: "偵測到生物識別設定已變更,請重新驗證身份。",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "重新驗證", style: .default) { _ in
// 導向驗證畫面
self.showAuthenticationScreen()
})
window?.rootViewController?.present(alert, animated: true)
}
}
平台差異比較
| 特性 | Android | iOS |
|---|---|---|
| 偵測方法 | 狀態輪詢 + Keystore 失效 | evaluatedPolicyDomainState 比對 |
| 即時性 | 需主動檢查 | 需主動檢查 |
| 隱私保護 | 不透露具體變更內容 | 不透露具體變更內容 |
| API 支援 | BiometricManager (API 23+) | LocalAuthentication (iOS 8+) |
| 變更粒度 | 狀態變化(可用/不可用) | 資料變更(新增/刪除指紋) |
| 實作複雜度 | 中等(需結合 Keystore) | 簡單(直接比對 state) |
安全性最佳實踐
1. 變更偵測時機
- App 啟動時:
onCreate()或applicationDidBecomeActive() - 進入敏感操作前:存取金融資料、修改設定前
- 定期背景檢查:每隔固定時間(如 24 小時)檢查一次
2. 變更後的處理措施
1. 記錄安全事件(timestamp、裝置資訊)
2. 清除本地敏感資料快取
3. 要求使用者重新驗證身份
4. 通知後端伺服器(可選)
5. 更新儲存的生物識別狀態
3. 隱私權合規
- 告知使用者:在隱私權政策中說明生物識別資料的處理方式
- 取得同意:首次使用生物識別時取得明確同意
- 最小化儲存:僅儲存必要的狀態資訊(如 hash 值),不儲存生物識別原始資料
- 安全儲存:使用 Keychain (iOS) 或 EncryptedSharedPreferences (Android)
常見問題 FAQ
Q1: 為什麼需要偵測生物識別變更?
A: 當使用者新增或刪除生物識別資料時,可能代表裝置擁有權轉移或安全威脅。金融、企業、醫療等敏感應用需要偵測這些變更以確保資料安全。
Q2: Android 能否直接取得變更的具體內容(如哪個指紋被刪除)?
A: 不行。基於隱私保護,Android 只提供整體狀態(可用/不可用),不會透露具體哪個生物識別資料被變更。
Q3: iOS 的 evaluatedPolicyDomainState 何時會改變?
A: 當以下情況發生時會改變:
- 新增或刪除 Touch ID 指紋
- 重設 Face ID
- 停用生物識別功能
Q4: 偵測到變更後應該採取什麼行動?
A: 建議採取以下措施:
- 記錄安全事件
- 清除敏感資料快取
- 要求使用者重新驗證
- 通知後端伺服器(金融應用建議)
Q5: 多久檢查一次生物識別變更比較合適?
A: 建議策略:
- App 每次啟動時檢查
- 進入敏感功能前檢查
- 背景定期檢查(每 24 小時)
Q6: 如何在 Android 上實作更精確的變更偵測?
A: 結合以下方法:
- 使用
setInvalidatedByBiometricEnrollment(true)的 Keystore 金鑰 - 定期檢查 BiometricManager 狀態
- 記錄狀態變更時間戳,分析異常模式
Q7: 是否需要將生物識別狀態同步到後端伺服器?
A: 取決於應用類型:
- 金融應用:建議同步,有助於風險控管
- 一般應用:可選,主要在本地處理即可
- 企業應用:建議同步,符合合規要求
總結
生物識別變更偵測是行動應用安全架構的重要環節。Android 與 iOS 雖然提供不同的實作方式,但核心概念相同:在保護使用者隱私的前提下,偵測生物識別設定的變更。
關鍵要點:
- Android:結合
BiometricManager狀態檢查與 Keystore 金鑰失效機制 - iOS:使用
evaluatedPolicyDomainState比對來偵測變更 - 隱私保護:兩個平台都不會透露具體變更內容
- 安全實踐:偵測到變更時應清除快取、要求重新驗證
- 合規要求:遵循隱私權政策,取得使用者同意
隨著生物識別技術的演進與隱私法規的強化,建議定期查閱 Android 與 iOS 官方文件,確保實作符合最新標準。