Разработчик
0,0
рейтинг
14 октября 2013 в 16:05

Разработка → Разблокировка экрана Android с помощью NFC

Для защиты от несанкционированного доступа к своему Nexus 4 я использую стандартную блокировку экрана с паролем. Но пароль приходится постоянно вводить вручную, а это немного напрягает. Блокировка с помощью графического ключа меня не впечатлила, так же как и PIN-код (слишком мало возможных комбинаций). Хотелось сильную защиту, с сохранением скорости разблокировки. Именно по этой причине я решил присмотреться к технологии NFC.

Готовые решения


Единственным готовым решением, которое я нашёл, для реализации разблокировки девайса с помощью метки, является программа NFCSecure. Она платная, а бесплатной версии нет. Посмотрев видео на его странице в Google Play, я сразу для себя решил, что ЭТО не стоит своих денег. Всё реализовано простейшим способом:
  1. Пользователь включает экран устройства и видит стандартный блокировщик экрана.
  2. Он его разблокирует.
  3. Появляется Activity NFCSecure, которое делает вид, что надёжно блокирует доступ к устройству (при нажатии на иконку разблокировки страница почему-то мигает, что не вселяет доверия).
  4. Прикладываем метку и окно закрывается.

Даже, если предположить, что это окно блокирует любые попытки физически добраться до стандартного лаунчера (сенсорные кнопки, физические кнопки, жест по статусной строке), оно ни в коем случае не реализует всю ту защиту, которую предоставляет стандартный экран блокировки. Стандартная блокировка гораздо более функциональна и блокирует даже доступ к девайсу как к накопителю, т.е. пока не разблокируете экран — доступа к файлам не получите.
В общем это приложение достаточно дырявое и защиту сравнимую со стандартным экраном блокировки оно не предоставляет.

Сделаем свою реализацию


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

Сканер меток работает не всегда

А точнее он не работает как минимум в двух случаях, которые нас интересуют:
  1. Когда экран выключен.
  2. Когда мы находимся на экране блокировки.

Я предполагаю, что в этих случаях сканер не работает по соображениям безопасности. После сканирования метки запускается наиболее подходящее приложение, и неизвестно что это приложение захочет сделать. Для примера, Google Wallet (судя по видео) требует пин-код и выбор карты перед тем как приложить устройство к терминалу.

Правила работы сканера находятся в системном приложении NfcNci.apk. Там то и находится константа которая определяет в каком состоянии должен быть девайс, чтобы работало сканирование (можно почитать здесь). Естественно эту константу нужно изменить. Многие разработчики выкладывают на xda-developers уже готовые модифицированные файлы NfcNci.apk под нужный вам девайс, поэтому я просто взял готовый файл и заменил им приложение на моём устройстве.
Константе можно установить как минимум одно из двух значений, которые позволят сканеру считывать метки при заблокированном экране:
  1. Сканер работает при выключенном экране.
  2. Сканер работает при включенном экране и даже с активной блокировкой.

Первое решение по словам форумчан жрёт около 35% батареи за 3 часа при том, что телефон просто лежал без дела. Поэтому лучше выбирать второй вариант, так как он вообще не тратит заряд + предотвратит случайную разблокировку и включение экрана, если метка будет находиться очень близко.
Конечно данное решение резко уменьшает порог вхождения обычных пользователей, так как теперь потребуется рутованный девайс и некоторые телодвижения, чтобы заменить оригинальное приложение. Но так как приложение не ориентированно на большие массы, то с этим можно смириться.

Нет простой возможности разблокировки

Опять же, по соображениям безопасности приложение на устройстве не может просто взять и разблокировать экран защищённый каким-либо методом (пароль, пин, паттерн и др.). На данный момент существует 2 стандартных решения, которые позволяют разблокировать экран:
  1. Класс KeyguardManager.KeyguardLock.
  2. Флаги окна FLAG_DISMISS_KEYGUARD и FLAG_SHOW_WHEN_LOCKED.

KeyguardManager.KeyguardLock

Этот класс содержит 2 метода: disableKeyguard() и reenableKeyguard(). Первый метод разблокирует только не защищёный экран. Если экран защищён каким-либо методом, то вызов будет проигнорирован. Метод reenableKeyguard() необходимо вызвать для повторной блокировки экрана, иначе блокировщик не будет запускаться после его выключения.
Минусы данного решения: нельзя разблокировать экран защищённый, допустим, паролем да ещё и надо по какому-то событию вызывать перезапуск экрана блокировки. Вдобавок данный класс является устаревшим начиная с API 13, так что на него не стоит надеяться.

Флаги окна

Флаги нужно устанавливать на родительское окно Activity. FLAG_DISMISS_KEYGUARD разблокирует экран только в том случае, если он не защищён. После закрытия окна блокировщик не будет восстанавливаться пока не выключится экран. FLAG_SHOW_WHEN_LOCKED лишь спрячет блокировщик (даже защищённый) и после закрытия окна он сразу же перейдёт на передний план.
То есть, опять же, эти флаги не смогут разблокировать защищённый экран. Максимум что можно сделать — показать своё окно поверх него.

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

Пишем обходные пути


Так как Android API не предоставляет нам красивых решений для разблокировки, то придётся писать костыли обходные пути.
В итоге было написано базовое приложение реализующее 3 метода разблокировки. Решил назвать его NFC Unlocker (ссылки на Google Play и исходники в конце поста). Реализованные обходные пути могут быть не стабильны, но это и так понятно исходя из их названия. Все эти методы требуют, чтобы пользователь вводил пароль в настройках приложения, а не в системе. Это сделано для того, чтобы мы могли восстанавливать/вводить (в зависимости от метода) пароль вместо пользователя.
После чтения метки ОС должна запустить наиболее подходящее Activity. Поэтому воспользоваться BroadcastReceiver’ом не получится. Далее я опишу эти методы.

Установка флага для окна Activity

И всё-таки флаг нам может помочь в реализации задуманного. Данное решение наиболее чистое, так как не требует рута и использует флаги окна, которые вполне себе разрешены. Для того, чтобы флаги сработали придётся очистить пароль методом DevicePolicyManager.resetPassword(). Для этого нам потребуются права администратора, которые приложение запросит у пользователя на странице настроек.
Алгоритм разблокировки таков:
  1. Пользователь сканирует метку, запускается наше Activity.
  2. Чистим пароль:
    ((DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)).resetPassword("", 0);
  3. Ставим флаг окну нашего Activity:
    getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
  4. Завершаем Activity в методе onAttachedToWindow, так как именно в нём к окну уже применён наш флаг.
  5. В методе onDestroy восстанавливаем пароль пользователя.

Использование KeyguardLock

Следующий метод использует устаревшее API, но тем не менее успешно выполняет свою задачу на Android 4.3. Так же как и в предыдущем методе нам придётся очистить пароль, чтобы разблокировка сработала.
Здесь алгоритм сложнее и с первого взгляда достаточно не стабилен (на практике всё гораздо лучше):
  1. Пользователь сканирует метку, запускается наше Activity.
  2. Чистим пароль:
    ((DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)).resetPassword("", 0).
  3. Разблокируем экран:
    KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Activity.KEYGUARD_SERVICE);
    KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("nfcunlocker");
    keyguardLock.disableKeyguard();
  4. Запускаем сервис, который в фоновом режиме создаст BroadcastReceiver, который будет принимать событие выключения экрана:
    ScreenReceiver screenReceiver = new ScreenReceiver();
    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
    registerReceiver(mReceiver, filter);
  5. Как только получено событие оповещающее о том, что экран выключен — включаем блокировку и восстанавливаем пароль.

Данный метод работает достаточно стабильно, но пользуется устаревшим API.

Ввод пароля через shell

Этот способ я придумал первым так как он достаточно прост, но требует root. В Андроиде с shell-а можно вызвать команду «input», которая позволяет вводить текст и эмулировать нажатия клавиш. Для ввода текста используется такой синтаксис:
input text "type your text here"
Эмуляция нажатий клавиш производится с помощью такой команды:
input keyevent KEYCODE
Список кодов клавиш можно найти здесь.
Алгоритм разблокировки у данного метода очень прост:
  1. Пользователь сканирует метку, запускается наше Activity.
  2. Вводим пароль с помощью shell команды «input», и с её же помощью посылаем код клавиши Enter.

Немного о самих метках


Про алгоритм выбора Activity при сканировании метки можно почитать здесь. Вкратце можно сказать, что ОС выбирает Activity на основании содержимого метки. Для гарантированного запуска нашего Activity нужно воспользоваться AAR (Android Application Records), что обозначает просто запись названия пакета приложения на метку. С помощью данного способа можно было бы гарантированно запускать разблокировку, но у меня не было под рукой меток, которые поддерживают стандарт NDEF. Поэтому я идентифицирую их по уникальному идентификатору.

Итог


А теперь подытожим плюсы и минусы интеграции с родным блокировщиком.
Плюсы:
  1. Не нарушаем защиту ОС.
  2. Разблокируем устройство просто приложив метку к устройству.
  3. Если метки нет рядом, то можно ввести пароль вручную.

Минусы:
  1. Высокий порог вхождения для пользователей. Нужен рут и модифицированный NfcNci.apk.
  2. Методы разблокировки могут работать не стабильно. Нужно выбрать подходящий.

По ссылке на Github есть ссылки на модифицированные файлы NfcNci.apk для некоторых популярных смартфонов.

Для демонстрации настройки и работы приложения я записал видео:


Ссылки:
Google Play
Github

P.S. За качество кода прошу не пинать. Я не Java-разработчик.
Павел @TheSteelRat
карма
6,0
рейтинг 0,0
Разработчик
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (37)

  • 0
    Ухты!
    А ещё можно объединить этот способ с RFID имплантацией и получится эдакий TouchID.
    • +1
      Я даже начал задумываться об этом, когда написал первую рабочую версию. Но потом одумался :).
    • +7
      *** шутка про отрубленную руку ***
  • +2
    А как можно переделать на графический ключ?
    • 0
      К сожалению по-простому это сделать не получится. Приложение работает поверх стандартного экрана блокировки и умеет работать только с паролями.
      Можно конечно заморочиться с эмулированием нажатий на экран, но это просто какой-то ужас будет :).
      Как я писал в самом начале — мне не нравится графический ключ. Лучше длинный пароль.
      • +2
        жаль… а то можно было бы и попробовать вашу программу. Одно удобство не променяешь на другое)
  • 0
    Что то подобное только через Xposed Framework.
    Правда у меня не хочет использовать проездной в качестве метки.
  • +6
    Пока не ставил приложение, но зачем в

    файлt src / com / steelrat / nfcunlocker / NFCApplication.java

    formUri = «www.bugsense.com/api/acra?api_key=c5c1eaf9»

    ?
    и далее коммит github.com/PaulAnnekov/nfcunlocker/commit/aae887a560bda7042f249bdc8953119640571fe2
    собственно добавление этой штуки? я конечно понимаю что это для отправки багрепортов, НО
    по моему, такого рода приложения (которые работают с паролями) вообще никогда и ни за что не должны ходить в интернет (разумеется по хорошему), если я такое вижу, то возникает какое-то недоверие…
    • +1
      Понимаю вас. Мне нужно как-то отлавливать и фиксить баги. Вы можете предложить альтернативу? Я надеялся, что Open Source даст вам увидеть, что я никаких паролей не отсылаю.
      • +2
        Я не Андроид-программист, поэтому предложить к сожалению ничего не могу :( Но опенсорс не всегда залог того, что ничего никуда не утекает, даже при наличии исходников, но это большой + Вам как разработчику.
        Сам недавно думал про NFC, но в контексте автоматического переключения профилей в Андроид при помощи RFID и уперса в то что пока не разблокируешь телефон, профиль не переключиться по метке :( было бы очень круто, если бы Вы реализовали и переключение профилей по меткам без разблокировки
      • 0
        Предложите пользователю отправить письмо с баг репортом. Плюсы:
        1. Не нужно интернет пермишена
        2. Есть контактный адрес отправителя

        ACRA из коробки позволяет это сделать.
        • 0
          Как-то мне интерфейс Gmail не очень нравится в качестве багтрекера :)
  • 0
    А такой вопрос: если уж мы меняем систему, то что мешает нам изменить логику блокировщика и переустановить его? (он же тоже реализован как приложение?)
    • 0
      Вендоры любят модифицировать исходники. Поэтому не получится взять исходники из AOSP, изменить их, скомпилить и заменить на устройстве.
      • 0
        Ну можно пойти путем наименьшего сопротивления и попробовать сделать это на основе CyanogenMod
  • +2
    Разблокировку по NFC-тегу, реализованную в штатной прошивке смартфона Moto X недавно представила Motorola.
  • 0
    А если нет NFC, можно сделать привязку по блютузу к браслету. Если телефон отнести от браслета он блокируется и требует ввода пароля, если браслет подключен то блокировка отсутствует. Браслет можно идентифицировать по хешу его ИД.
    • 0
      Постоянное пингование браслета по BT сожрет очень много энергии, в т.ч. и у самого браслета (где, как вы понимаете, большую батарейку поставить нельзя).
      • 0
        Постоянного пинга не потребуется. Проверка наличия устройства проверяется в момент разблокировки. К примеру блютуз браслеты для индикации входящих, в ждущем режиме работают около 50 часов и около 2х в полной нагрузке. Учитывая что большинство современных смартфонов работают несколько суток, время работы соизмеримо.
        Но то что разряжаться комплект будет быстро согласен.

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

        В общем то идею можно развить, и блютуз браслет будет выступать в роли токена, для крипто хранилища в смартфоне. Под такое дело и логику работы и протоколы допилят и браслет сможет неделю если не две автономно работать.
        • 0
          Можно, в принципе, на браслете просто сделать кнопку для нажатия. При сопряжении происходит генерация уникальных ключей (причем можно на экране браслета показывать токен, который нужно ввести на телефоне при сопряжении), а при нажатии кнопки — разблокировка.
          • 0
            Тогда получается по сути токен с одноразовым паролем, и блютуз становится не нужным.

            Идея в том что, если недалеко от смартфона есть некое устройство то блокировка снимается автоматически, без ввода паролей и прочего, и можно удобно пользоваться смартфоном. Если же устройства нет, то придётся вводить пароль.

            Но как вариант, почему бы и нет. Учитывая, что смартфон стал рабочим компьютером, а безопасность данных становится всё более актуальной, возможно скоро такие устройства действительно появятся.
            • 0
              Нене, токен с браслета вводится один раз, при сопряжении. Если браслет от аппарата отцепляется — то нужно сопрягать снова, с вводом нового токена.
              Разблокировка при сопряженных аппаратах происходит при нажатии кнопки.
              Кнопка здесь нужна, чтобы уменьшить энергопотребление, и чуточку повысить безопасность (например, долгое нажатие выключает браслет).
      • 0
        BT-гарнитура работает часами, смартфон с ней разряжается не быстрей, чем с проводной, BT 4.0 LE позволяет вот таким маложрущим девайсам держать коннект гораздо дольше и есть практически во всех новых мобилках.
        • 0
          Емнип, перечисленные аппараты работают немного не так, как нужно для наших целей.
          Насколько я помню, там фактическая установка связи и передача данных происходят по событиям, т.е. например, входящий звонок — лезем на гарнитуру, и т.д.
          А в случае же с постоянным пингом нам нужно будет постоянно держать открытым канал, излучать и принимать пакетики.
  • 0
    Что-то подобное было на кикстартере с NFC кольцом (NFC Ring).

    Проект уже пошел в производство.
    • 0
      Угадайте какое приложение занимается разблокировкой…
      • 0
        Так это и хорошо! Ещё один вариант использования. Однако функции разблокировки при выключенном экране явно не хватает и тут и там.
        • 0
          Вы статью читали? NFC Secure работает не очень хорошо. Про разблокировку при выключенном экране я тоже писал.
          • 0
            Может быть я не правильно интерпретировал, но посмотрите пожалуйста вот это приложение. или тоже всё завязано на NFCSecure?
            Статью я читал. Поправьте, если что не так.
            • 0
              Для того, чтобы его использовать надо какой-то ключ. Наверное предоставляется вместе с кольцом.
              Но по тому что видно в видео + по надписи «Powered by NFCSecure» на экране авторизации в приложении, можно предположить, что это тоже самое, что и NFCSecure, только стандартный экран блокировки вообще отключён. Вместо него запускается это приложение. Никаких плюшек (виджеты) стандартного блокировщика, судя по всему, не будет.
  • +3
    Блокировка с помощью графического ключа меня не впечатлила, так же как и PIN-код (слишком мало возможных комбинаций).


    Пин-код из 4 цифр: 10^4 комбинаций. Мат. ожидание времени на перебор (1 PIN/сек): 1.4 часа.
    Пин-код из 6 цифр: 10^6 комбинаций, 136 часов.
    Паттерн-лок: 389488 комбинаций, 53 часа.
    Ах да, при всём этом, после 5 или 10 попыток между попытками создаётся задержка в 30 секунд, а после 20 телефон просто блокируется.

    Ну а в вашем случае (и большинстве остальных) можно и вовсе ключ считать незаметно. Или речь идёт о защите неуловимого Джо?
    • 0
      Пин-код из 4-ёх цифр и графический ключ легко запоминаются. Стоит лишь хоть раз подглянуть.
      Более 4-ёх символов — это уже пароль по терминалогии Андроида. Его достаточно долго нужно вводить и мне это не нравится. Особенно не удобно это делать на ходу.
      Я сейчас просто выставляю пароль на 10 символов, а разблокирую браслетом. Так гораздо быстрее. А если нет браслета под рукой — пароль ввожу.
      • 0
        Вынужден поспорить по поводу паттерна — выключите отображение пути, потренируйтесь 3-5 раз и будете вводить так, что никто в жизни не разглядит ваш ключ.
        Я вообще всеми руками за подобные методы увеличения безопасности, при условии что они действительно, кхм, увеличивают безопасность. Но, к сожалению, RFID/NFC абсолютно безполезен для аутентификации без challenge-response хотя бы на симметричном крипто (асимметричное на пассивных метках вроде не реализуемо ещё), но как-то я не вижу таких меток в свободном доступе.
  • 0
    У мотороллы есть отличное штатное решение. Клипса на ремень, разблокирующая телефон в одно касание.
  • +1
    А где можно купить NFC браслет или кольцо?
    • 0
      Кольцо недавно успешно выстрелило на кикстартере. подробнее можете глянуть на nfcring.com
      Сейчас они в процессе запуская их на конвеер. Обещают к концу года всем спонсорам раздать

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