1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-BIO.md 37 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Подробное описание технологии биометрической аутентификации для мобильных систем

Без сомнения, многие уже знакомы с биометрической аутентификацией — использование отпечатков пальцев для входа в систему или оплаты через FaceID стало достаточно распространенным. Поэтому при работе над любым мобильным проектом, будь то Android, iOS, React Native или Flutter, рано или поздно придется столкнуться с этой задачей.

Конечно, различия могут заключаться в уровне понимания платформ и доступных интерфейсов. В данной статье мы рассмотрим особенности использования системы биометрической аутентификации на Android и iOS, какие шаги следует предпринять и что стоит учесть при реализации этого функционала.

⚠️ Внимание: Эта статья больше ориентирована на исследование возможностей и решений возникающих вопросов при внедрении биометрической аутентификации, а не на подробное руководство по использованию API. Также обратите внимание, что материал довольно объемный.

Начнем с базового понятия: независимо от того, использует ли ваш проект Android или iOS, а также независимо от типа биометрической информации (отпечатки пальцев или FaceID), если вы используете предоставляемые системой API, разработчики не имеют доступа к данным биометрической информации пользователей. Таким образом, вы можете использовать только системные API и получать ответы в виде успеха или ошибки.image-20220329172335926

1. Android

История развития биометрической аутентификации на Android весьма запутана. На данный момент можно выделить два основных этапа:

  • FingerprintManager (API 23)
  • BiometricPrompt (API 28)

Как показано на следующем рисунке, существуют две основные службы, поддерживающие возможности API биометрической аутентификации. Однако важно отметить, что FingerprintManager был помечен как устаревший (@Deprecated) начиная с API 28 (Android P) вместе со всеми совместимыми версиями в androidx, такими как FingerprintManagerCompat. Это связано с тем, что официальные разработчики предлагают более простое и готовое к использованию решение в виде androidx.biometrics.BiometricPrompt.

image-20220329172806492

1.1. Использование BiometricPrompt

Первым шагом при использовании BiometricPrompt является добавление необходимых разрешений в манифест вашего приложения.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.biometric">
    <uses-permission android:name="android.permission.USE_BIOMETRIC" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
</manifest>

Затем вызывается BiometricPrompt, чтобы создать системное окно с информацией, подробности можно увидеть на следующем рисунке:

image-20220329175140111

После этого устанавливается AuthenticationCallback и вызывается authenticate, затем ожидаем результат авторизации в успешном callback:```java biometricPrompt = new BiometricPrompt(activity, uiThreadExecutor, authenticationCallback); biometricPrompt.authenticate(promptInfo);


Конечно, вышеупомянутый код недостаточен и требует дополнительной информации:

- Например, следует использовать `FragmentActivity`;
- Проверка устройства на наличие поддержки биометрического аутентификационного метода (хотя существуют устройства, которые его не поддерживают);
- Определение того, какое именно биометрическое средство поддерживается, хотя `BiometricPrompt` обычно сам это решает, если доступно несколько вариантов;

Если аутентификация не удалась, то можно получить соответствующий код ошибки в методе `onAuthenticationError`.| onAuthenticationError             | Тип                                                                                                                   |
 | --------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
 | BIOMETRIC_ERROR_LOCKOUT           | Операция отменена, так как API заблокировано из-за слишком большого количества попыток (например, при нескольких неудачных попытках распознать отпечаток пальца). |
 | BIOMETRIC_ERROR_LOCKOUT_PERMANENT | Из-за слишком частых случаев BIOMETRIC_ERROR_LOCKOUT операция отменена; это действительно блокировка.                   |
 | BIOMETRIC_ERROR_NO_SPACE          | Недостаточно свободного места                                                                                         |
 | BIOMETRIC_ERROR_TIMEOUT           | Время ожидания истекло                                                                                                |
 | BIOMETRIC_ERROR_UNABLE_TO_PROCESS | Аномалия сенсора или невозможность обработки текущей информации                                                       |
 | BIOMETRIC_ERROR_USER_CANCELED     | Пользователь отменил операцию                                                                                         |
 | BIOMETRIC_ERROR_NO_BIOMETRIC      | У пользователя нет зарегистрированных биометрических данных                                                          |
 | BIOMETRIC_ERROR_CANCELED          | Операция отменена из-за недоступности биометрического сенсора                                                         |
 | BIOMETRIC_ERROR_HW_NOT_PRESENT    | Устройство не имеет биометрического сенсора                                                                          |
 | BIOMETRIC_ERROR_HW_UNAVAILABLE    | Устройство не может использовать аппаратное обеспечение                                                               || BIOMETRIC_ERROR_VENDOR            | Если существует ситуация, которая не относится ни к одному из вышеперечисленных типов, Other                               |### 1.2 Биометрическое уведомление (BiometricPrompt) с возможностью кастомизации

После простого внедрения `BiometricPrompt`, вы можете задаться вопросом: "BiometricPrompt действительно удобен, но его внешний вид немного устарел. Можно ли его кастомизировать?"

**К сожалению, нет**, `BiometricPrompt` нельзя кастомизировать UI, даже если вы хотите поменять цвета — это будет сложно. Если вы посмотрите на [биометрический](https://android.googlesource.com/platform/frameworks/support/+/androidx-main/biometric) код, то заметите, что официальные разработчики не планировали предоставить такую возможность, за исключением случая, когда вы сами скопируете этот код и создадите свою реализацию. Одной из причин такого дизайна, как мне кажется, является **встроенное скрытое расположение сенсора отпечатков пальцев**.

> В официальной статье ["Переход с FingerprintManager на BiometricPrompt"](https://medium.com/androiddevelopers/migrating-from-fingerprintmanager-to-biometricprompt-4bc5f570dccd) говорится, что следует отказаться от использования файлов с макетами отпечатков пальцев, поскольку они больше не нужны вам. Биометрическая библиотека AndroidX включает в себя стандартизованный UI.

Что такое стандартизованный UI? Ниже приведены три устройства, использующие `BiometricPrompt`. Вы можете заметить:- Первое и второе устройства отличаются лишь местоположением элементов, всё остальное одинаково;
- Третье устройство имеет встроенный сенсор отпечатка пальца, и его пользовательский интерфейс полностью уникален и зависит от производителя;![image-20220329183129880](http://img.cdn.guoshuyu.cn/20220627_Flutter-BIO/image4)

**Поэтому при использовании `BiometricPrompt` вам не придётся беспокоиться о внешнем виде, поскольку выбора нет. Также вам не придётся заботиться о типах биометрических сенсоров на вашем устройстве, поскольку производители оборудования (OEM) уже реализуют эти возможности согласно требованиям CDD и стандартному пользовательскому интерфейсу (UI)**, например, UI Samsung выглядит следующим образом:

![](http://img.cdn.guoshuyu.cn/20220627_Flutter-BIO/image5)


> [Документация по совместимости Android (CDD)](https://source.android.com/compatibility/android-cdd#7_3_10_biometric_sensors) описывает уровень безопасности биометрических сенсоров, а также в рамках фреймворка `BiometricFragment` и `FingerprintDialogFragment` являются скрытыми (`@hide`). Даже если вы просто просмотрите библиотеку `androidx.biometric:biometric.aar`, вы не найдёте макет `BiometricFragment`, а только макет `FingerprintDialogFragment`.

То есть нет способа кастомизировать UI? Есть несколько вариантов:

- Продолжайте использовать `FingerprintManager`, хотя он помечен как устаревший, но всё ещё работает и корректно выполняется логика на Android 11. Ниже представлен сравнительный анализ одного и того же устройства на Android 11, использующего `FingerprintManager` и `BiometricPrompt`:  ![image-20220329202726403](http://img.cdn.guoshuyu.cn/20220627_Flutter-BIO/image6)

- Используйте библиотеку [Soter](https://github.com/Tencent/soter) от Tencent; мы рассмотрим это позже;

### 1.3 Вход в систему + BiometricPromptПосле того как мы рассмотрели вызов и UI, давайте обсудим использование `BiometricPrompt` в сценарии входа в систему. Официальная версия предоставляет демонстрационный пример для сценария входа в систему [здесь](https://github.com/android/security-samples/tree/master/BiometricLoginKotlin). В этом разделе мы рассмотрим общую бизнес-логику, а конкретные реализации можно найти в официальном примере [BiometricLoginKotlin](https://github.com/android/security-samples/tree/master/BiometricLoginKotlin).

Как было сказано ранее, биометрическая аутентификация предназначена только для предоставления результатов проверки, поэтому при использовании в сценарии входа в систему основная задача `BiometricPrompt` заключается в выполнении аутентификации и шифрования:

![image-20220329162115306](http://img.cdn.guoshuyu.cn/20220627_Flutter-BIO/image7)

Как показано на приведённой выше схеме, после успешного входа в систему мы получаем информацию о токене пользователя, который может содержать чувствительные данные, такие как пароль. Для обеспечения безопасности этот токен не хранится в открытом виде, а шифруется с помощью `BiometricPrompt`.

Процесс шифрования состоит из следующих шагов:- Используется объект `KeyStore`, чтобы получить секретный ключ (`SecretKey`) с паролем;
- Ключ `SecretKey` используется для создания объекта `Cipher`, который является стандартным объектом для шифрования и расшифровки данных в Java;
- Объект `CryptoObject` создается с использованием `Cipher`, и затем он передается в метод биометрической аутентификации;
- После успешной аутентификации возвращается объект `AuthenticationResult`, содержащий объект `cryptoObject?.cipher` и значение `cipher.iv`;
- Токен шифруется с использованием `cryptoObject?.cipher`, а вместе с значением `cipher.iv` они сохраняются в `SharedPreferences`.Не кажется ли вам всё это сложным? Проще говоря, мы используем секретный ключ, доступ к которому предоставляется только после успешной аутентификации пользователя, чтобы зашифровать токен. Таким образом, даже если токен будет украден, он будет безопасен для нас.

В процессе использования `KeyStore` есть операция `setUserAuthenticationRequired(true)`, которая указывает, что ключ можно использовать только после успешной аутентификации пользователя. Когда эта операция установлена в `true`, то есть: **пользователь должен пройти аутентификацию на этом устройстве Android с помощью подмножества своих данных экрана блокировки (например, пароля/PIN/образца или биометрического отпечатка), чтобы получить доступ к ключу**.

То есть ключ будет создан только при наличии безопасной блокировки экрана. Если эта безопасная блокировка будет отключена (перенастроена как "никак", в режиме без проверки личности пользователя или принудительно переустановлена), то ключ *необратимо станет недействительным*.

> Также можно использовать метод `setUserAuthenticationValidityDurationSeconds`, чтобы требовать наличия хотя бы одного биометрического фактора для использования ключа. Как только этот метод будет установлен как true, если пользователь зарегистрирует новый биометрический фактор, ключ также станет *необратимо недействительным*.**Итак, можно заметить, что данный процесс связывает ключ с уровнем безопасности системы, таким образом защищаясь от утечки информации, такой как токены**, а благодаря интеграции `CryptoObject` и `KeyStore` после успешной авторизации, система становится более защищённой от атак, таких как rooting.

Обратный процесс получения данных аналогичен:

- Получение шифрованного токена и iv из `SharedPreferences`;
- Создание объекта `Cipher` с использованием `SecretKey`, но теперь с учётом сохраненного iv;
- Вызов биометрической аутентификации через `BiometricPrompt.CryptoObject(cipher)`;
- Шифрование токена с помощью `cryptoObject?.cipher` после успешной аутентификации, чтобы получить первоначальный токен;

![image-20220329162133600](http://img.cdn.guoshuyu.cn/2bk.png)

Как видно, **основная идея заключается в использовании `CryptoObject?.Cipher` для шифрования и расшифровки данных после прохождения аутентификации с помощью `BiometricPrompt`, тем самым обеспечивая защиту конфиденциальной информации на уровне системы.**

Наконец, стоит отметить ещё один важный момент: хотя обычно мы этим не занимаемся, в `BiometricPrompt` существуют два понятия — ***auth-per-use*** и ***time-bound***:- ***auth-per-use*** — это ключ, который требует аутентификации при каждом использовании. Это реализовано через вызов метода `BiometricPrompt.CryptoObject(cipher)`.
- ***time-bound*** — это ключ, действительный только в течение определённого времени. Его срок действия может быть установлен с помощью `setUserAuthenticationValidityDurationSeconds`. Если установить его очень коротким, например, 5 секунд, поведение будет похожим на ***auth-per-use***.> Для получения дополнительной информации можно обратиться к официальным материалам [биометрическая-аутентификация-на-Android](https://medium.com/androiddevelopers/biometric-authentication-on-android-part-1-264523bce85d).

### 1.4. SOTER от Tencent

Как уже упоминалось, на Android существует технология SOTER, которую Tencent внедрила для использования отпечатков пальцев в WeChat, превратив её в полноценную систему биометрической аутентификации: SOTER.

SOTER сотрудничает с производителями смартфонов, предоставляя дополнительные меры безопасности сверх существующих системных интерфейсов через безопасные зоны, независимые от операционной системы устройства (TEE — Trusted Execution Environment), что снижает сложность разработки и затраты на адаптацию приложений (TA). **Это позволяет обеспечивать безопасное аутентификационное авторизование даже в случае недоверия внешней среды.**> TEE (Trusted Execution Environment) представляет собой область выполнения, которая работает независимо от операционной системы устройства. В стандарте SOTER все операции, связанные со шифрованием ключей, подписью данных, проверкой отпечатков пальцев и передачей чувствительных данных, выполняются внутри TEE. **Кроме того, корневой ключ устройства, используемый в SOTER, записывается производителем на этапе производства, что решает проблему недоверия корневых ключей. Этот корневой ключ используется как базовый доверенный элемент для генерации других ключей, что позволяет завершить процесс. Все производители смартфонов, сотрудничающие с WeChat, оснащены аппаратной TEE, прошедшей сертификацию через платформу безопасности Tencent и команду безопасности платежей WeChat, соответствующую стандарту SOTER.**![image-20220329214046518](http://img.cdn.guoshuyu.cn/20220627_Flutter-BIO/image9)

Кратко говоря, это сторонняя библиотека, обеспечивающая прямое взаимодействие с производителями и предоставляющая возможность интеграции с сервисами проверки. Последний раз она обновлялась примерно пять месяцев назад, но есть ли у неё проблемы?

Проблема заключается в том, что **она может использоваться только совместно с производителями смартфонов, работающими с WeChat**, а также иногда возникают странные ошибки на некоторых версиях операционной системы производителей, такие как:

- MiUI13 — ошибка при привязке службы;
- Ошибки API уровня на HarmonyOS;
- Непредвиденные аварийные завершения работы;

Однако она способна реализовать базовые возможности, аналогичные платежам WeChat, поэтому выбор между ней и другими решениями зависит от ваших бизнес-потребностей.

> Поддерживаемые модели можно найти здесь: [#сколько устройств уже поддерживают tencent-soter](https://github.com/Tencent/soter/wiki#сколько_устройств_уже_поддерживают_tencent-soter)


## iOS

По сравнению с Android, где требуется различение версий операционной системы и производителей для использования `fingerprints`, `faces` и `irises`, использование Face ID и Touch ID на iOS значительно удобнее и проще.

Рассмотрим использование биометрии на iOS. Во-первых, необходимо добавить описание в файл `Info.plist`:```xml
<key>NSFaceIDUsageDescription</key>
<string>Почему мое приложение использует Face ID для аутентификации?</string>

Затем импортируйте заголовочный файл #import <LocalAuthentication/LocalAuthentication.h>, а затем создайте объект LAContext для выполнения операции аутентификации. Ниже приведён список соответствующих кодов ошибок:| Код ошибки | Тип ошибки | | ------------------------- | --------------------------------------- | | LAErrorSystemCancel | Аутентификация была отменена системой, например при смене активного приложения | | LAErrorUserCancel | Пользователь отменил процесс аутентификации | | LAErrorAuthenticationFailed | Процесс аутентификации завершился неудачей | | LAErrorPasscodeNotSet | Устройство не настроено на использование пароля | | LAErrorBiometryNotAvailable | Биометрический метод недоступен, например если он был отключен | | LAErrorBiometryNotEnrolled | Биометрический метод недоступен, так как пользователь еще не прошел обучение | | LAErrorUserFallback | Пользователь выбрал ввод пароля |

Аналогично, стоит отметить, что iOS не предоставляет возможности для создания пользовательского интерфейса для биометрической аутентификации, поэтому вы можете использовать только те средства, которые предлагает система.

В этом плане разработчики Android могут позавидовать iOS, поскольку любые проблемы являются проблемами системы и не требуют исправления.

Кроме того, давайте рассмотрим основной процесс использования биометрической аутентификации для входа в систему на iOS:- После получения информации о токене проверьте пользователя на соответствие TouchID/FaceID;

  • При успешной проверке сохраните информацию о токене и другие данные в ключевом хранилище (ключевое хранилище — это место хранения данных, предназначенное для хранения конфиденциальных данных, таких как пароли и сертификаты);
  • После успешного сохранения, при следующем входе используйте TouchID/FaceID для получения соответствующей информации;image-20220329223329042

Основные моменты здесь следующие:

  • Уровень доступа: Например, требуется ли каждый раз выполнять аутентификацию перед доступом к данным;

  • Уровень аутентификации: То есть какие условия должны выполняться для доступа к данным;Пример: Для доступа к ключевому хранилищу сначала необходимо создать объект управления доступом (accessControl). Обычно это можно сделать с помощью функции SecAccessControlCreateWithFlags, где важным параметром является уровень доступа:

  • kSecAttrAccessibleAfterFirstUnlock: Ключ недоступен до следующего ввода пароля после первого входа в систему.

  • kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly: Ключ недоступен до следующего ввода пароля после первого входа в систему, но только на данном устройстве.

  • kSecAttrAccessibleWhenUnlocked: Ключ доступен после разблокировки устройства.

  • kSecAttrAccessibleWhenUnlockedThisDeviceOnly: Ключ доступен после разблокировки устройства, но только на данном устройстве.

  • kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly: Ключ доступен после установки пароля, но только на данном устройстве.

  • kSecAttrAccessibleAlways: Всегда доступен, но устарел.

  • kSecAttrAccessibleAlwaysThisDeviceOnly: Всегда доступен, но не может быть перемещён на другие устройства, устарел.

Похожие сценарии обычно используют kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, а также флаги SecAccessControlCreateFlags, которые主要用于指定希望用户在访问 ключницы (keychain) 时的 ограничения. В таких сценариях обычно используется userPresence:

Основные сценарии часто используют `kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly`, а также флаги `SecAccessControlCreateFlags`, чтобы указать желаемые ограничения при доступе к ключевой информации. В этих случаях обычно используется `userPresence`.

Перевод:

Основные сценарии часто используют kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, а также флаги SecAccessControlCreateFlags, чтобы указать желаемые ограничения при доступе к ключевой информации. В этих случаях обычно используется userPresence.- devicePasscode: ограничивает доступ с использованием устройства-пароля;

  • biometryAny: позволяет использовать любую зарегистрированную биометрию (Touch ID или Face ID);
  • biometryCurrentSet: ограничивает доступ с использованием текущей зарегистрированной биометрии (Touch ID или Face ID);
  • userPresence: ограничивает доступ с использованием биометрии или пароля;
  • watch: позволяет использовать Apple Watch для доступа.

После создания объекта accessControl его можно установить через kSecAttrAccessControl и затем нормально сохранить информацию в ключнице (keychain). При сохранении в ключнице есть возможность выбора опционального kSecClass:

  • kSecClassGenericPassword: универсальный пароль;
  • kSecClassInternetPassword: интернет-пароль;
  • kSecClassCertificate: сертификат;
  • kSecClassKey: шифрующий ключ;
  • kSecClassIdentity: удостоверение личности.

Конечно, заметили ли вы, что при обсуждении accessControl и keychain не было упоминания LAContext?

На самом деле, при создании accessControl существует соответствующий параметр kSecUseAuthenticationContext для установки LAContext в процессе аутентификации ключницы. Однако этот параметр может и не использоваться, что зависит от следующих условий:- Если он не указан, но проект требует аутентификации, будет автоматически создан новый LAContext, который используется один раз и затем выбрасывается;

  • Если используется ранее аутентифицированный LAContext, операция успешно завершается без необходимости повторной аутентификации пользователя;
  • Если используется ранее не аутентифицированный LAContext, система попытается выполнить аутентификацию на этом контексте. Если она успешна, LAContext можно будет переиспользовать в последующих операциях с ключницей.> Дополнительно см. официальную документацию: accessing_keychain_items_with_face_id_or_touch_id.

Как видно, на iOS достаточно просто настроить эти параметры, так как системный уровень предоставляет ограниченные возможности.

⚠️ Уведомление: если вам требуется скрыть возможность ввода пароля после неудачной попытки биометрической аутентификации на iOS, вы можете настроить LAContext с помощью context.localizedFallbackTitle = "".

III. Последнее слово

Хотя данная статья не обучает вас использованию биометрической аутентификации на Android или iOS, она представляет собой сводку основных концепций и проблем, связанных с этим вопросом. Мы уверены, что эта статья окажется полезной для всех исследователей, занимающихся разработкой биометрической аутентификации. Наконец, как обычно, если у вас есть какие-либо вопросы или предложения по этому поводу, приветствуются ваши комментарии и отзывы.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master