Данная статья является переводом соответствующей статьи Aditya Agrawal. Оригинал доступен по ссылке.

Небезопасное хранение данных занимает второе место в списке OWASP Mobile Top 10.

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

    Источники угроз:

  • Мобильные вредоносные приложения
  • Физический доступ к устройству

    Внутренние носители

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

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

Для демонстрации я использовал приложение FourGoats. Данные каждого приложения находятся в папке /data/data устройства Android. В папке каждого приложения существует папка shared_prefs, папка базы данных и другие папки, созданные приложением. Файлы в этих папках попадают в категорию Internal Storage (Внутренний Носитель). В большинстве приложений можно увидеть, что файлы в папке shared_prefs доступны для чтения всем пользователям (в том числе файлы с чувствительными данными).

8_1

На рисунке выше можно увидеть, что все файлы в папке shared_prefs приложения FourGoats доступны для чтения всем пользователям. То есть, любое вредоносное приложение может получить доступ к содержимому этих файлов (даже без прав root). Главное, на что здесь требуется обратить внимание, это то, что иногда разработчики оставляют в таких файлах и пары логин-пароль, что, очевидно, может привести к их компрометации.

    Как это исправить

  • Не используйте режимы MODE_WORLD_READABLE или MODE_WORLD_WRITABLE для файлов, предназначенных для IPC, т.к. эти режимы не только не предоставляют возможность ограничивать доступ к данным для отдельных приложений, но и не предоставляют никаких инструментов для контроля формата данных. Если требуется совместное использование данных с другими приложениями, то следует использовать Content Provider, который предоставляет права чтения и записи другим приложениям, а также может предоставлять права динамическии, отдельно в каждом конкретном случае.
  • Не полагайтесь исключительно на жёстко встроенные в приложения (hardcoded) ключи шифрования, когда храните чувствительные данные, т.к. эти ключи могут быть получены при декомпиляции приложения.
  • Принимайте во внимание возможность введения дополнительного слоя шифрования, кроме механизмов шифрования, предоставляемых непосредственно операционной системой.

    Внешние носители

Файлы, созданные на внешних хранилищах, таких, как SD-карты, доступны для чтения и записи всем пользователям. Т.к. внешние носители могут быть извлечены пользователем, а также быть изменены любым приложением, не следует хранить чувствительные данные на внешних носителях.
Также, как и с данными из любых недоверенных источников, следует проверять входные параметры при обработке данных из внешнего носителя. Строго рекомендуется не хранить исполняемые файлы или файлы с классами на внешних носителях перед динамической загрузкой. Если приложение получает исполняемые файлы из внешних носителей, то перед динамической загрузкой эти файлы должны быть подписаны (и затем проверены) криптографической подписью.

    Content Provider’ы

Я уже говорил о Content Provider’ах и основанных на их использовании способах, которыми приложения могут хранить данные и предоставлять к ним общий доступ.

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

Давайте начнём

8_2

Можно увидеть, что экспортируются два Content Provider’а

8_3

Таким образом, используя модуль app.provider.finduri, мы нашли несколько экспортируемых URI Content Provider’ов, к которым можно получить доступ через другие приложения, установленные на том же устройстве.

Можно увидеть, что есть два похожих URI:
content://com.mwr.example.sieve.DBContentProvider/keys
и
content://com.mwr.example.sieve.DBContentProvider/keys/

Давайте попробуем сделать запрос к каждому из них

8_4

8_5

Для доступа к первому требуется разрешение com.mwr.example.sieve.READ_KEYS, но для второго не требуется каких-либо разрешений. Таким образом, у нас есть мастер-пароль и пин от приложения, которое управляет паролями других приложений. Это ли не опасно?

Давайте попробуем изменить значение поля Password с iampassword1234 на iampassword5555

8_6

Мы также можем получить доступ к паролям, сохранённым в этом менеджере паролей, сделав запрос к другому экспортируемому URI

8_7

Я бы посоветовал попробовать использовать упомянутый модуль Drozer для этого уязвимого приложения. И если вы «застряли» на каком-либо модуле, то попробуйте запустить эту же команду с ключом -help.

Как это исправить

  • Если Content Provider используется только этого приложения, то следует установить для него параметр android:exported=false в AndroidManifest.xml. Если же этот Content Provider экспортируется намеренно, то следует также указать разрешения на чтение или запись.
  • Если Content Provider используется для предоставления совместного доступа данным между вашими собственными приложениями, то следует установить атрибут android:protectionLevel в значение «signature«.
  • При осуществлении доступа к Content Provider’у следует использовать методы для параметризованных запросов, такие, как query(), update() и delete() для избежания потенциальных SQL-инъекций из недоверенных источников.