生物識別變更偵測:Android 與 iOS 平台完整實作指南

🌏 Read the English version

生物識別變更偵測: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 雖然提供不同的實作方式,但核心概念相同:在保護使用者隱私的前提下,偵測生物識別設定的變更。

關鍵要點:

  1. Android:結合 BiometricManager 狀態檢查與 Keystore 金鑰失效機制
  2. iOS:使用 evaluatedPolicyDomainState 比對來偵測變更
  3. 隱私保護:兩個平台都不會透露具體變更內容
  4. 安全實踐:偵測到變更時應清除快取、要求重新驗證
  5. 合規要求:遵循隱私權政策,取得使用者同意

隨著生物識別技術的演進與隱私法規的強化,建議定期查閱 Android 與 iOS 官方文件,確保實作符合最新標準。

相關文章

Leave a Comment