DPC (Device Policy Controller): админим блокировку экрана в Android

от автора

Если вы занимаетесь защитой от несанкционированного доступа к устройству, то наверняка ваш самый первый и самый простой шаг — это защита разблокировки экрана. Графический пароль, цифровой PIN-код, доступ по биометрии (например, скан отпечатка пальцев, распознавание лица) и так далее — эти механизмы знает каждый.

Я же расскажу, как можно настроить способ блокировки/разблокировки экрана с помощью Device Policy Controller (DPC) — приложения-администратора нужного профиля устройства (если на устройстве развернуты несколько профилей — например, и рабочий, и личный) или же всего устройства в целом.

Статья будет полезна тем, кто интересуется безопасностью мобильных устройств и различными способами управления ею. А в конце, если тема будет вам интересна, я добавлю еще несколько полезных ссылок на посты моих коллег по команде мобильной разработки «Лаборатории Касперского».

Как и для многих других опций расширенного управления девайсом, доступ к методам настройки пароля осуществляется через объект класса DevicePolicyManager, который предоставляет API для управления политиками на устройстве.

Сразу стоит отметить несколько общих моментов для многих методов класса DevicePolicyManager (в том числе эти черты касаются тех методов, которые мы будем рассматривать ниже):

  • Большинство методов этого класса требуют в качестве параметра объект класса ComponentName — это идентификатор компонента (Activity, Service, BroadcastReceiver или ContentProvider), содержащий информацию о пэкадже приложения и имени класса внутри этого пэкаджа.
  • Если приложение не является администратором, не имеет прав Device Owner или Profile Owner или же не запрошены соответствующие разрешения (оговорим отдельно необходимые разрешения (permissions) для каждого из методов, если они необходимы), то при вызове методов этого класса будет выброшено исключение SecurityException.

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

Работа с минимальными значениями пароля

Начнем рассматривать методы настройки пароля с настройки его минимальной длины.

В первую очередь посмотрим простой и прямолинейный метод DevicePolicyManager.setPasswordMinimumLength(), который, как мы и оговаривали выше, принимает идентификатор текущего компонента ComponentName и, очевидно, минимальное количество символов пароля. Действие этого метода не распространяется на текущий установленный пароль, однако в дальнейшем пользователь не сможет установить пароль более короткий, чем задано методом. Если же передать параметром значение 0, то прежде установленные ограничения на длину снимаются.

Чтобы иметь больший контроль над настройкой пароля, ОС разрешает не только задать минимальную длину самого пароля, но также и указать его тип через метод DevicePolicyManager.setPasswordQuality(), передавая ему одну из определенных в Android констант (важно: они доступны, начиная с разных API level):

PASSWORD_QUALITY_UNSPECIFIED

Нет требований к паролю

PASSWORD_QUALITY_BIOMETRIC_WEAK

Разрешено использование слабых биометрических способов, которые по надежности сопоставимы с трехзначным PIN-кодом

PASSWORD_QUALITY_SOMETHING

Политика требует наличия какого-либо способа блокировки: PIN, пароль, паттерн, но не предъявляет конкретных требований к типу

PASSWORD_QUALITY_NUMERIC

Политика требует наличия пароля с использованием хотя бы только цифр или любого более надежного пароля (например, буквенно-цифрового)

PASSWORD_QUALITY_NUMERIC_COMPLEX

Политика требует наличия пароля с использованием хотя бы только цифр, но без повторений одной и той же цифры (8888) и без последовательностей (0987 и даже 0864 не подойдут)

PASSWORD_QUALITY_ALPHABETIC

Политика требует наличия пароля с использованием букв (или других нечисловых символов) или любого более надежного пароля (например, буквенно-цифрового)

PASSWORD_QUALITY_ALPHANUMERIC

Политика требует наличия пароля с использованием букв и цифр или любого более надежного пароля (например, буквенно-цифрового с использованием специальных символов)

PASSWORD_QUALITY_COMPLEX

Политика требует наличия пароля, построенного в соответствии с заданными ограничениями на минимальное количество букв (отдельно можно указать общее число букв, а также число строчных и прописных букв), цифр, специальных символов, небуквенных символов. Для этого мы можем воспользоваться «уточняющими» методами класса DevicePolicyManager, позволяющими с помощью параметров задать минимальное число символов того или иного типа:

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

Пароль готов! Но есть нюанс…

Мы рассмотрели функции setPasswordMinimumLength() и setPasswordQuality(), позволяющие задать минимальную длину и требования к типу пароля (а иногда и требования к наличию определенных символов в пароле). Но все было бы слишком просто, если бы на этом все и ограничилось 🙂

Этот API был введен в Android 2.2.x (Froyo) API level 8, однако в Android 12 (Snow Cone) API level 31 такие методы были запрещены для устройств в режиме BYOD (Bring Your Own Device) — когда сотрудники используют личные девайсы в рабочих целях. Так у админов с правами Device Owner и Profile Owner сохраняется возможность использовать эти «приемы», однако Google рекомендует работать с новым методом, который, начиная с API level 31, может заменить эти два. Речь идет о setRequiredPasswordComplexity(), который вводит новую систему градаций сложности пароля: она совмещает количественную составляющую (ограничение на количество символов) и качественную (ограничение на типы используемых вариантов блокировки).

На вход этот метод принимает как раз одну из констант новой градации. Рассмотрим их подробнее.

PASSWORD_COMPLEXITY_NONE

Нет никакого пароля

PASSWORD_COMPLEXITY_LOW

К этой группе относятся:

  • Паттерны (графические рисунки как метод разблокировки);
  • PIN с повторяющимися цифрами (8888) или последовательностями (0987, 0864).

PASSWORD_COMPLEXITY_MEDIUM

К этой группе относятся:

  • PIN без повторов или последовательных цифр длиной от 4 символов;
  • Буквенный пароль длиной от 4 символов;
  • Буквенно-цифровой пароль длиной от 4 символов.

PASSWORD_COMPLEXITY_HIGH

К этой группе относятся:

  • PIN без повторов или последовательных цифр длиной от 8 символов;
  • Буквенный пароль длиной от 6 символов;
  • Буквенно-цифровой пароль длиной от 6 символов.

В случае если в текущем профиле уже были установлены настройки пароля с помощью методов setPasswordMinimumLength(), setPasswordQuality() и сопутствующими методами setPasswordMinimumXXX(), использование метода setRequiredPasswordComplexity() очищает любые из этих старых настроек.

Проверяем соответствие пароля требованиям

Теперь, когда сложность способа входа задана, можно проверить, удовлетворяет ли текущий метод разблокировки заданным условиям, с помощью метода DevicePolicyManager.isActivePasswordSufficient(). Нужно учесть, что запустить эту проверку можно только в том случае, если пользователь разблокировал экран, иначе метод выбросит IllegalStateException.

Если пароль не удовлетворяет требованиям, можно предложить пользователю обновить пароль, запустив активити установки типа блокировки экрана для текущего пользователя из настроек устройства. Это можно сделать, запустив интент с action ACTION_SET_NEW_PASSWORD.

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

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

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

Есть и другие методы.

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

Предъявляем «политики» из документаций и работаем с коллбэками

Стоит отметить, что некоторые из рассмотренных методов требуют у админа наличия задекларированных типов политик, которыми он может оперировать. В документации рассмотренных методов присутствует указание на необходимость (где она есть) объявить тот или иной их тип. В противном случае, если вызвать метод, не имея соответствующего прописанного типа политики, метод завершится с ошибкой SecurityException. В этом случае соответствующий тип нужно добавить в файл res/xml/device_admin.xml, например, так:

<device-admin xmlns:android="http://schemas.android.com/apk/res/android">     <uses-policies>         <limit-password />     </uses-policies> </device-admin>  

И указать путь к этому файлу в файле манифеста приложения в разделе нашего DeviceAdminReceiver, как это сделано ниже:

<receiver android:name=".policy.DeviceAdmin"     ... >     <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin" />     ... </receiver>  

DeviceAdminReceiver также предоставляет несколько полезных коллбэков, с помощью которых можно отслеживать разные события, связанные с экранным паролем:

  • onPasswordChanged — вызывается в момент, когда пользователь сменил пароль;
  • onPasswordExpiring — вызывается периодически, когда срок действия пароля близок к завершению или когда он истек;
  • onPasswordFailed — вызывается после каждой неудачной попытки ввода пароля;
  • onPasswordSucceeded — вызывается в случае успешного ввода пароля пользователем.

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

Также хочется обратить внимание, что ссылки ведут на коллбэки, доступные, начиная с Android 8.0 (Oreo) API level 26, однако аналогичные методы с теми же названиями существуют и для предыдущих версий. Единственное отличие — они не имеют в списке параметров данных о пользователе.

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

Если вам интересна тема безопасности мобильных устройств на Android, то мою статью хорошо дополнят следующие посты:

А если вы уже «собаку съели» в мобильной разработке и «этот мир уже вам абсолютно понятен» — добро пожаловать к нам в команду 🙂


ссылка на оригинал статьи https://habr.com/ru/articles/854584/