Приветствую тебя, дорогой читатель! Многие разработчики используют возможности Account Manager(AM) в своих приложениях. И правильно делают, ведь этот инструмент позволяет упростить некоторые вещи. Он позволяет хранить пароль, токен, да и в принципе любые строковые данные юзера. Так же позволяет автоматически обновлять токен, если тот протухает, и много других полезных штук. Но у этого удобства есть и другая сторона — безопасность. Из-за этого собственно я и написал данный текст.

Раз AM позволяет хранить такие важные данные как пароль и токен, то наверно он просто обязан это делать безопасно, ведь если они утекут, то ничего хорошего не получится. Вы можете сказать, что на рутованых андроид девайсах ничто не хранится безопасно, и я тут соглашусь. Однако если бы все ограничивалось только рутом, то не читать бы вам сие «произведение». Чтобы рассказать, ради чего мы тут собрались, я начну с самого начала.

Вообще для работы с AM в приложении нужно сделать несколько телодвижений и создать два компонента — наследника AbstractAccountAuthenticator и Service (подробней тут). Последний придется зарегистрировать в манифесте приложения таким образом:

        <service
            android:name=".account.AuthenticatorService"
            android:exported="false">
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator" />
            </intent-filter>

            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/authenticator" />
        </service>

А еще, если вы заметили, то нам надо создать в ресурсах некий xml-файл с именем authenticator.xml. Хотя название тут не важно, а важно содержимое. Оно то и играет ключевую роль рассказа. Выглядит файл внутри вот так:

<account-authenticator 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="@string/account_type"
    android:label="@string/app_name" />

Параметр label — отвечает за название в списке аккаунтов в настройках девайса, а самое интересно несет в себе accountType. Без него приложение не сможет добавлять и получать аккаунты. А еще с помощью этого параметра можно перехватить аккаунты другого приложения даже на девайсах без рута. Давайте посмотрим, как это может произойти.

На устройстве существует приложение А с accountType = «someType», это приложение создает акаунт, добавляет в него токен, пароль и прочую информацию. В один прекрасный момент на устройство устанавливается приложение B с таким же accountType = «someType». И вот если удалить приложение A, то все созданные аккаунты перейдут во власть приложения B с полным доступом. Обратное тоже верно, аккаунты приложения B передадутся приложению A, если удалить B.

Пример на видео:


Опережая вопросы про подписи apk, это не зависит от того, каким ключом было подписано приложение, релизным или дебажным, передача произойдет в любом случае. Ужасно, правда?

Все это можно проделать в плоть до API версии 23. Исправлено только с выходом андроид 7.0(API 24). Печалит в этой ситуации ничтожно малый процент устройств с этой версией андроида. Кстати, узнал я об этой проблеме из доклада по безопасности в андроид. К сожалению в тексте, пересказе презентации, об этом ничего нет вообще, а вот в видео об этом упомянули вскользь, не придав особого значения.

Так же что же ты предлагаешь? — можете спросить вы. А я предлагаю вам два варианта решения проблемы. Первый — продолжать пользоваться AM, но хранить в нем все важные данные в зашифрованном виде. Если вы перестали доверять AM, можно продолжать им пользоваться, но не хранить в нем важные данные и воспользоваться AM в связке со вторым вариантом. Второй — вообще отказаться от AM и пользоваться хранилищем, которое можно шифровать. Например SQLite в связке с sqlcipher или Realm, который поддерживает шифрование из коробки. Я выбрал последний. Тут пример для realm, где показано, как генерировать и хранить ключ шифрования.

Примеры кода в статье приводить не стал, так как в этом нет смысла. С исходниками жертвы и перехватчика вы сможете ознакомиться на гитхабе.

Спасибо за внимание!
Поделиться с друзьями
-->

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


  1. lopatoid
    05.11.2016 13:05
    +1

    Чуть-чуть подробностей:
    https://sites.google.com/site/droidnotsecure/vulnerabilies/credential-residue/accountmanager


  1. petrovichtim
    05.11.2016 18:22

    Спасибо за статью. Как я понимаю удалить любое приложение нельзя без рута?


    1. andreich
      06.11.2016 10:56

      Если приложение установлено как системное, то удалить его нельзя. Можно удалить любое приложение, которое пользователь сам устанавливал.


  1. RainyWill
    05.11.2016 20:42

    В принципе можно


  1. MERCH_music
    07.11.2016 09:33

    тэги улыбнули