Приложение использует Android KeyStore, но не проверяет, что ключ аппаратно защищён (Hardware-Backed)
Описание
Android KeyStore может хранить ключи либо в защищённом аппаратном модуле (TEE / StrongBox HSM), либо в программном контейнере.
Если после генерации/импорта ключа приложение не проверяет признак isInsideSecureHardware()
или не валидирует attestation-подпись, оно рискует использовать ключ, который:
- хранится в системной памяти и может быть извлечён на рутованном устройстве;
- был импортирован злоумышленником вместо сгенерированного аппаратно.
Google рекомендует подтверждать аппаратную защиту через Key Attestation или инспекцию KeyInfo
перед использованием ключа.
Потенциальные последствия
- Извлечение приватного ключа при root-доступе, что позволяет расшифровать базы, токены или сетевой трафик.
- Подмена ключа вредоносным ПО: фальшивый ключ хранится в софте, но проходит валидацию приложения и открывает MITM-канал.
- Несоответствие требованиям безопасности (OWASP MASVS - M9, Google Play Data Safety).
- Неисполнение регуляторных норм (например, PSD2/SCA требует аппаратного ХСК для хранения банковских ключей).
Рекомендации
-
Проверяйте
isInsideSecureHardware()
сразу после генерации/получения ключаKeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); SecretKey key = (SecretKey) ks.getKey(alias, null); KeyFactory kf = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore"); KeyInfo info = kf.getKeySpec(key, KeyInfo.class); if (!info.isInsideSecureHardware()) { throw new SecurityException("Key is NOT hardware-backed"); }
Пример проверки обсуждается в сообществе разработчиков. (Stack Overflow)
-
Используйте Key Attestation для критичных операций
- Запросите цепочку сертификатов (
attestationChallenge
) и проверьте, чтоattestationSecurityLevel == STRONGBOX
илиTEE
. - Храните отпечаток сертификата на сервере и сравнивайте при каждом запуске. (Android Developers)
- Запросите цепочку сертификатов (
-
При генерации ключа укажите StrongBox/TEE флаг
new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setIsStrongBoxBacked(true) // требуем StrongBox .setUserAuthenticationRequired(true) // привязываем к биометрии/PIN .build();
На устройствах без StrongBox обработайте
StrongBoxUnavailableException
(Android Developers) -
Откажитесь от импорта симметричных ключей, если можно сгенерировать их внутри TEE/StrongBox. Импортированные ключи никогда не могут быть помечены как hardware-backed.
-
Для устройств до API 23 рассмотрите использование Trusted Execution Environment сторонних SDK или внешнего HSM; старые версии не поддерживают
KeyInfo
.
Дополнительные рекомендации
- Сохраняйте результаты attestation на бэкенде и анализируйте отклонения (например, key перестал быть hardware-backed после обновления прошивки).
- Периодически выполняйте принудительное re-key с новой проверкой аппаратной защиты.
- Уведомляйте пользователя, если устройство не поддерживает аппаратный KeyStore, и предлагайте ограничения функционала.