Русский
Русский
English
Статистика
Реклама

Аndroid

Виды биометрии в мобильном приложении

22.11.2020 10:20:58 | Автор: admin
Для идентификации пользователя в приложении можно использовать биометрию например, сканеры радужной оболочки глаза, геометрии лица или отпечатка пальца. Хотя эти технологии известны и популярны, у начинающих разработчиков из-за недостатка информации до сих пор возникают те или иные вопросы.

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



Основные виды биометрии


Идентификация пользователей необходима во многих приложениях, которые обрабатывают личные данные, например, в онлайн-банках. Так, в России с 2018 года действует Единая биометрическая система (ЕБС), с помощью которой клиенты могут пользоваться услугами банков удаленно. По рекомендациям Банка России, в 2020 году все банки должны иметь возможность собирать биометрические данные пользователей.

Согласно исследованию Spiceworks, более 60% компаний Европы и Северной Америки используют биометрию для защиты данных и считают, что этот метод надежнее, чем пин-код или сочетание логина и пароля. 10% респондентов уверены, что для идентификации достаточно только биометрии, тогда как другие компании настаивают на использовании дополнительных способов.

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

  • Сканер отпечатка пальца (fingerprint) 57%
  • Сканер геометрии лица (face ID) 14%
  • Прочие методы: сканеры радужной оболочки глаза (IRIS) и геометрии руки (3-5%).

Существуют и другие способы аутентификации, например, голосовая биометрия однако, их надежность ниже, поэтому обращаются к ним реже.

Рассмотрим особенности нескольких перечисленных способов.

1) Сканер отпечатка пальца (fingerprint)


Для того, чтобы узнать пользователя по отпечатку пальца и безопасно хранить его данные, каждый производитель мобильных устройств предлагает свои возможности. Так, на устройствах Apple образец отпечатка пальца проводится через хеш-функцию перед сохранением в защищенный вычислительном модуль. Все процессы, связанные с Touch ID, происходят именно в этом модуле, и извлечь такие данные невозможно.

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



Freepik.com

2) Сканер геометрии лица (face ID)


Если приложение идентифицирует пользователя по лицу, сканирование осуществляют за счет емкостной камеры. По сравнению с предыдущим способом, здесь требуется еще более сложный алгоритм, требующий высокой точности захвата изображения и распределения более 30 тысяч контрольных точек по изображению лица пользователя. В свою очередь, это определяет более высокие требования к камере смартфона.

По сути дела, емкостный сканер изучает лицо пользователя, выстраивая геометрическую модель и преобразуя её в результаты вычисления, которые можно хранить. Во время авторизации результат вычисления (с учетом погрешности) для конкретного пользователя сопоставляется с результатом, хранящимся в памяти.



Adobe Stock

При этом не все устройства предоставляют полноценные возможности для распознавания лиц. Бывают случаи, когда производители ограничиваются 2D-сканированием с помощью обычной камеры. Как правило, при этом на картинке выделяется лицо, которое можно сравнить с другими изображениями в базе как в игре Найди 10 отличий. Если приложению не удастся найти отличия, то пользователь может быть распознан как владелец. В этом случае есть риск, что потенциальному злоумышленнику удастся разблокировать приложение, просто просканировав фотографию владельца.

3) Сканер радужной оболочки глаза (IRIS)


Важно помнить, что IRIS это не сканер сетчатки глаза. Проще говоря, эта технология сканирует радужную оболочку, которая окружает зрачок, тогда как сетчатка располагается внутри глаза на задней стенке.

Сканер определяет те или иные особенности внешности пользователя и геометрическую форму радужки, используя емкостные камеры.

Хотя такой способ биометрической защиты может показаться перспективным, у него есть свои уязвимости. С одной стороны, для снятия блокировки недостаточно найти и предъявить фотографию владельца, ведь камера определяет объем изображения. Однако, такой риск выше при одновременном использовании фотографии и контактных линз. Сканер сетчатки глаза в этом отношении может быть безопаснее, поскольку данные владельца невозможно получить в открытых источниках или угадать.



Adobe Stock

Как работает распознавание


При использовании любого из перечисленных биометрических сканеров, как правило, 100% точности недостижима. Когда пользователь сканирует отпечаток пальца, получившийся рисунок зависит от силы нажатия, смещения на долю миллиметра вправо или влево, наличия незначительных травм кожи. В результаты несколько сканов лица или отпечатков пальца одного пользователя всегда содержат различия.

При этом для авторизации по лицу или отпечатку пальца используют метод нечеткого поиска.



Блок-схема с симметричными криптографическими ключами (источник)

В этом случае приложение ищет не полностью совпадающие элементы, как при хешировании паролей, а наиболее похожие друг на друга сущности. Например, если вы авторизуетесь по отпечатку пальца, то совпадение рисунка на 90% очень хороший показатель, который фактически подтверждает личность владельца отпечатка.

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

Рассмотрим, как будет выглядеть процесс регистрации:

  • Биометрическое сканирование захватывает изображение.
  • Алгоритм извлекает из изображения стабильные и воспроизводимые векторы.
  • Происходит генерация открытого и закрытого кода, при этом закрытый код хешируется.
  • Симметричные или асимметричные криптографические ключи выдаются для сгенерированного биометрического хеш-кода.
  • При использовании асимметричных криптографических ключей происходит сохранение открытого ключа и удаление из системы закрытого ключа. Биометрические данные в этих случаях не сохраняются.

Верификация происходит следующим образом:
  • Биометрическое сканирование захватывает изображение.
  • Алгоритм извлекает те же стабильные функции, что и при регистрации.
  • Публичный код сообщает системе, где находятся функции для поиска частного кода.
  • Создается один и тот же закрытый код, для аутентификации выдаются одни и те же криптографические ключи и хеш.


Блок-схема с асимметричными криптографическими ключами (источник)

Чтобы преобразование было повторяемым, перед его началом биометрический сигнал должен быть надлежащим образом зарегистрирован. Эта проблема частично решена с помощью ряда методов, описанных в научной литературе.

Подводя итоги


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

Как безболезненно мигрировать с RxJava на Kotlin CoroutinesFlow

11.01.2021 10:24:00 | Автор: admin
Для выполнения асинхронных операций в Android-приложениях, где нужна загрузка и обработка любых данных, долгое время использовали RxJava и о том, как перейти на RxJava 3, мы уже писали в нашем блоге. Сейчас на смену фреймворку постепенно приходят инструменты Kotlin Coroutines+Flow. Актуальность этой связки подтверждается тем, что Google сделал Kotlin приоритетным языком для Android-разработки.

Корутины позволяют тратить меньше системных ресурсов, чем RxJava. Кроме того, поскольку они являются частью Kotlin, Android предоставляет удобные инструменты для работы с ними например, viewModelScope и lifecycleScope. В этой статье мы рассмотрим use cases, распространенные в Rx Java, и то, какие возможности вы получите при переходе на Flow.



Переключение потоков и создание


Для начала сравним, как происходит переключение потоков в RxJava и Flow.

RxJava


Observable.create<Int> { emitter ->emitter.onNext(1)emitter.onNext(2)emitter.onNext(3)emitter.onComplete()}.observeOn(Schedulers.io()).map {printThread(map1 value = $it)it + it}.doOnNext { printThread(after map1 -> $it) }.observeOn(Schedulers.computation()).map {printThread(map2 value = $it)it * it}.doOnNext { printThread(after map2 -> $it) }.observeOn(Schedulers.single()).subscribe ({printThread(On Next $it)},{printThread(On Error)},{printThread(On Complete)})


При этом сложение выполняется в IO шедулере, умножение в computation шедулере, а подписка в single.

Flow


Повторим этот же пример для Flow:

launch {flow {emit(1)emit(2)emit(3)}.map {printThread(map1 value = $it)it + it}.onEach { printThread(after map1 -> $it) }.flowOn(Dispatchers.IO).map {printThread(map2 value = $it)it * it}.onEach { printThread(after map2 -> $it) }.flowOn(Dispatchers.Default).onCompletion { printThread(onCompletion) }.collect { printThread(received value $it) }}


В результате можно отметить следующее:

1) observeOn переключает поток, в котором будут выполняться последующие операторы, а flowOn определяет диспетчер выполнения для предыдущих операторов.

2) Метод collect() будет выполняться в том же диспетчере, что и launch, а emit данных будет происходить в Dispatchers.IO. Метод subscribe() будет выполняться в Schedulers.single(), потому что идет после него.

3) Flow также имеет стандартные методы создания flow:

  • flowOf(): в примере можно было бы использовать Observable.fromArray(1, 2, 3) и flowOf(1, 2, 3)
  • extenstion function asFlow(), который превращает Iterable, Sequence, массивы во flow
  • билдер flow { }

4) В данном примере Flow, как и RxJava, представляет собой cold stream данных: до вызова методов collect() и subscribe() никакой обработки происходить не будет.

5) В RxJava нужно явно вызывать emitter.onComplete(). В Flow метод onCompletion() будет автоматически вызываться после окончания блока flow { }.

6) При попытке сделать эмит данных из другого диспетчера, с помощью withContext, например, приведет к ошибке.

Exception in thread main java.lang.IllegalStateException: Flow invariant is violated:
Flow was collected in [BlockingCoroutine{Active}@5df83c81, BlockingEventLoop@3383bcd],
but emission happened in [DispatchedCoroutine{Active}@7fbc37eb, Dispatchers.IO].
Please refer to 'flow' documentation or use 'flowOn' instead

Подписка и отписка на источник данных


В RxJava метод Observable.subscribe() возвращает объект Disposable. Он служит для отписки от источника данных, когда новые порции данных от текущего источника уже не нужны. Важно иметь доступ к этому объекту, чтобы вовремя отписываться и избегать утечек.

Для Flow ситуация схожа: так как метод collect() suspend метод, он может быть запущен только внутри корутины. Следовательно, отписка от flow происходит в момент отмены Job корутины:

val job = scope.launch {flow.collect { }}job.cancel() // тут произойдет отписка от flow

В случае же использования viewModelScope об этом заботиться не нужно: все корутины, запущенные в рамках этого scope, будут отменены, когда ViewModel будет очищена, т.е. вызовется метод ViewModel.onCleared(). Для lifecycleScope ситуация аналогична: запущенные в его рамках корутины будут отменены, когда соответствующий Lifecycle будет уничтожен.

Обработка ошибок


В RxJava есть метод onError(), который будет вызван в случае возникновения какой-либо ошибки и на вход получит данные о ней. В Flow тоже есть такой метод, он называется catch(). Рассмотрим следующий пример.

RxJava


Observable.fromArray(1, 2, 3).map {val divider = Random.Default.nextInt(0, 1)it / divider}.subscribe({ value ->println(value)},{ e ->println(e)})


При возникновении ArithmeticException будет срабатывать onError(), и информация об ошибке будет напечатана в консоль.

Flow


flowOf(1, 2, 3).map {val divider = Random.Default.nextInt(0, 1)it / divider}.catch { e -> println(e) }.collect { println(it) }


Этот же пример, переписанный на flow, можно представить с помощью catch { }, который под капотом имеет вид привычной конструкции try/catch.

Операторы RxJava onErrorResumeNext и onErrorReturn можно представить в виде:

catch { emit(defaultValue) } // onErrorReturn

catch { emitAll(fallbackFlow) } // onErrorResumeNext

В Flow, как и в RxJava, есть операторы retry и retryWhen, позволяющие повторить операции в случае возникновения ошибки.

Операторы


Рассмотрим наиболее распространенные операторы RxJava и найдем их аналоги из Flow.



Подробнее с операторами Flow можно познакомиться здесь.

Некоторые операторы Flow (например, merge) помечены как экспериментальные или отсутствующие. Их api может измениться (как, например, для flatMapMerge), или их могут задепрекейтить, то есть они станут недоступны. Это важно помнить при работе с Flow. При этом отсутствие некоторых операторов компенсируется тем, что flow всегда можно собрать в список и работать уже с ним. В стандартной библиотеке Kotlin есть множество функций для работы со списками.

Также у Flow отсутствуют отдельные операторы троттлинга и другие операторы, которые работают с временными промежутками. Это можно объяснить молодостью библиотеки, а также тем, что, согласно словам разработчика Kotlin Романа Елизарова, команда Jetbrains не планирует раздувать библиотеку множеством операторов, оставляя разработчикам возможность компоновать нужные операторы самостоятельно, предоставляя им удобные блоки для сборки.

Backpressure


Backpressure это ситуация, когда производитель данных выдает элементы подписчику быстрее, чем тот их может обработать. Готовые данные, в ожидании того, как подписчик сможет их обработать, складываются в буфер Observable. Проблема такого подхода в том, что буфер может переполниться, вызвав OutOfMemoryError.

В ситуациях, когда возможен backpressure, для Observable нужно применять различные механизмы для предотвращения ошибки MissingBackpressureException.

После появления в RxJava 2 Flowable произошло разделение на источники данных с поддержкой backpressure (Flowable) и Observable, которые теперь не поддерживают backpressure. При работе с RxJava требуется правильно выбрать тип источника данных для корректной работы с ним.

У Flow backpressure заложена в Kotlin suspending functions. Если сборщик flow не может принимать новые данные в настоящий момент, он приостанавливает источник. Возобновление происходит позднее, когда сборщик flow снова сможет получать данные. Таким образом, в Kotlin нет необходимости выбирать тип источника данных, в отличие от RxJava.

Hot streams


Горячий источник рассылает новые порции данных по мере их появления, вне зависимости от того, есть ли активные подписчики. Новые подписчики получат не всю сгенерированную последовательность данных с самого начала, а только те данные, что были сгенерированы после подписки. В этом отличие горячих и холодных источников: холодные не начинают генерацию данных, пока нет хотя бы одного подписчика, а новые подписчики получают всю последовательность.

Горячие источники данных полезны, например, при подписке на события от View: при этом нужно получать только новые события, нет смысла обрабатывать заново все пользовательские действия. Также мы не можем запретить пользователю нажимать на экран до тех пор, пока мы не будем готовы обрабатывать его действия. Для обработки событий от View в реактивном виде существует библиотека RxBinding, которая имеет поддержку RxJava3.

В Kotlin Flow есть свои возможности для работы с горячим flow, который производит данные вне зависимости от наличия подписчиков и выдает новые данные одновременно всем имеющимся подписчикам. Для этого можно использовать Channel, SharedFlow, чтобы отправлять новые порции данных одновременно всем подписанным сборщикам.

Кстати, для Flow тоже есть отличная библиотека для обработки событий от View Corbind. В ней есть поддержка большинства Android-виджетов.

RxJava Subjects


Subject в RxJava это специальный элемент, который одновременно является источником данных и подписчиком. Он может подписаться на один или несколько источников данных, получать от них порции данных и отдавать их своим подписчикам.

Аналог Subject в Flow это Channel, в частности, BroadcastChannel. Существуют различные варианты их реализации: с буферизацией данных (ArrayBroadcastChannel), с хранением только последнего элемента (ConflatedBroadcastChannel). Но важно помнить, что, так как библиотека Kotlin Flow молода и постоянно развивается, ее части могут меняться. Так получилось и в случае с BroadcastChannel: в своей статье Роман Елизаров сообщил, что, начиная с версии 1.4 будет предложено лучшее решение shared flows, а BroadcastChannel ждет deprecation в ближайшем будущем.

Заключение


В данной статье мы сравнили RxJava и Kotlin Flow, рассмотрели их схожие моменты и аналоги частей RxJava в Flow. При этом Flow хорошо подойдет в качестве инструмента для обработки событий в реактивном стиле в проектах на Kotlin, использующих паттерн MVVM: благодаря viewModelScope и lifecycleScope запускать корутины можно быстро и удобно, не боясь утечек. В связи с тем, что популярность Kotlin и его инструментов растет, а также этот язык является приоритетным для разработки Android-приложений, в ближайшие годы связка Coroutines+Flow может заменить RxJava скорее всего, новые проекты будут написаны именно с помощью нее. На первый взгляд, миграция с RxJava на Flow не представляется болезненной, потому что в обоих случаях есть похожие операторы и разделение общей концепции Reactive streams. Кроме того, Kotlin имеет достаточно большое комьюнити, которое постоянно развивается и помогает разработчикам в изучении новых возможностей.

А вы готовы мигрировать на корутины? Приглашаем поделиться мнениями!
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru