Как добавить вход по Face ID и отпечатку пальца в приложение
Практика3 минРедакция Innovialabs
Коротко
Биометрия не передает приложению отпечаток или лицо — она лишь разблокирует ключ или токен в защищенном хранилище устройства, поэтому правильный вход по Face ID строится на Keychain/Keystore, а не на проверке «да/нет».
Как это работает на самом деле
Приложение никогда не получает отпечаток или снимок лица. Сравнение выполняет защищенный модуль устройства: Secure Enclave на iPhone, TEE или отдельный чип на Android. Приложению система сообщает только результат.
Есть два способа использовать этот результат:
- Проверка «да/нет». Приложение спрашивает «пользователь подтвердил?» и получает
true. Просто, но на взломанном устройстве ответ можно подменить. - Криптографическая привязка. Секрет (например, refresh token) или ключ шифрования хранится в Keychain/Keystore с условием «выдать только после биометрии». Без успешной проверки данные физически недоступны.
Для входа в аккаунт используйте второй вариант. Первый подходит для некритичного: скрыть содержимое экрана, подтвердить безобидное действие.
Типичная схема входа
- Пользователь первый раз входит обычным способом: телефон и код, пароль или Apple/Google.
- Приложение предлагает включить вход по Face ID или отпечатку.
- Refresh token сохраняется в защищенное хранилище с требованием биометрии.
- При следующем запуске система показывает биометрический запрос, хранилище отдает токен, приложение получает новую сессию с сервера.
Сервер ничего не знает о биометрии — он видит обычное обновление токена.
Реализация на iOS
Используйте Keychain с флагом доступа .biometryCurrentSet и добавьте в Info.plist ключ NSFaceIDUsageDescription с понятным объяснением — без него запрос Face ID не сработает.
let access = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
.biometryCurrentSet,
nil
)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "refresh_token",
kSecValueData as String: tokenData,
kSecAttrAccessControl as String: access
]
SecItemAdd(query as CFDictionary, nil)
При чтении этого элемента система сама покажет Face ID или Touch ID.
Реализация на Android
Создайте ключ в Android Keystore, который требует аутентификации пользователя, и передайте Cipher в BiometricPrompt через CryptoObject. Расшифровать токен можно только после успешной проверки.
val spec = KeyGenParameterSpec.Builder(
"session_key",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build()
Для криптографической привязки запрашивайте класс BIOMETRIC_STRONG — слабые методы разблокировки ее не поддерживают.
Flutter и React Native
- Flutter: пакет
local_authдает только проверку «да/нет». Для привязки к хранилищу используйтеflutter_secure_storageс параметрами доступа по биометрии или специализированные пакеты, работающие через Keystore/Keychain. - React Native:
expo-local-authentication— тоже «да/нет». Для хранения токена под биометрией подходятreact-native-keychainсaccessControlилиreact-native-biometrics, который создает ключи и подписывает данные.
Перед выбором пакета проверьте, действительно ли он использует Keychain/Keystore под капотом, а не просто показывает системный диалог.
Резервный сценарий и смена отпечатков
- Fallback. Биометрия может не сработать: мокрые пальцы, маска, блокировка после нескольких неудачных попыток. Всегда оставляйте путь входа через код устройства, PIN приложения или полный вход.
- Новый отпечаток или лицо. С флагами
.biometryCurrentSetиsetInvalidatedByBiometricEnrollment(true)добавление новой биометрии делает сохраненный секрет недоступным, на Android появитсяKeyPermanentlyInvalidatedException. Это защита, а не баг: обработайте ее, удалите старый секрет, попросите войти полностью и снова включить биометрию. - Отключенная биометрия. Если пользователь удалил все отпечатки или выключил Face ID, сразу переводите на обычный вход.
На что не стоит полагаться
- Биометрия подтверждает «кто-то из зарегистрированных», а не конкретного человека. На устройстве может быть отпечаток члена семьи.
- Это не замена первого входа и не способ восстановить доступ.
- Для крупных операций (переводы, смена телефона) добавляйте серверную проверку: подпись ключом из защищенного хранилища или повторный код.
- Проверка «да/нет» без хранилища легко обходится на рутованных и джейлбрейк-устройствах.