Ключи в AndroidKeyStore создаются без требования биометрической инвалидации
Описание
Проверка показала, что при генерации ключей в Android KeyStore не устанавливается флаг .setInvalidatedByBiometricEnrollment(true)
(доступен с API 24 в KeyGenParameterSpec.Builder
).
Когда этот параметр не задан (false
— значение по умолчанию), ключ остаётся действительным даже после добавления, изменения или удаления биометрических данных (отпечатков, лица). Это означает, что злоумышленник, получив физический доступ к устройству, может:
- зарегистрировать собственный отпечаток/лицо;
- пройти Biometric Prompt;
- использовать ключ для расшифровки конфиденциальных данных или подписи транзакций.
Google и OWASP рекомендуют включать инвалидацию, чтобы любой изменённый биометрический шаблон инвалидировал существующий ключ и требовал его повторной генерации.
Потенциальные последствия
- Обход биометрической защиты. Атакующий добавляет свой отпечаток и моментально получает доступ к хранилищу без знания PIN/пароля.
- Утечка приватных данных (токены, сеансовые ключи, офлайн-БД).
- Несоответствие требованиям OWASP MASVS (M9) и внутренним политикам компаний-эмитентов, где смена/добавление биометрии должна автоматически отозвать криптоключи.
- Повышенный риск при устройстве, выданном сотруднику
Рекомендации
-
Всегда включайте инвалидацию при генерации ключа
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setUserAuthenticationRequired(true) // требуется биометрия/PIN .setUserAuthenticationValidityDurationSeconds(0) // каждый раз .setInvalidatedByBiometricEnrollment(true) // ← критический флаг .build();
-
Обрабатывайте
KeyPermanentlyInvalidatedException
При обращении к ключу ловите исключение и регинирируйте ключи после обновления отпечатков:
-
Проверяйте свойство
isInvalidatedByBiometricEnrollment()
черезKeyInfo
После загрузки ключа убедитесь, что флаг действительно установлен; иначе — откажите в операции.
-
Используйте StrongBox / TEE + BiometricPrompt
Совмещайте аппаратное хранилище и обязательную аутентификацию, чтобы даже при рут-доступе ключ не экспортировался.
Ссылки
- Android Developers –
setInvalidatedByBiometricEnrollment
- OWASP MASTG – Local Authentication (§ “setInvalidatedByBiometricEnrollment”)
- Medium – “Handling Key Invalidation with Biometric Prompt”
- Stack Overflow – Why
setInvalidatedByBiometricEnrollment
matters - KeyPermanentlyInvalidatedException – API doc