Страницы

Поиск по вопросам

Показаны сообщения с ярлыком contentprovider. Показать все сообщения
Показаны сообщения с ярлыком contentprovider. Показать все сообщения

воскресенье, 22 декабря 2019 г.

Применение ContentProvider при разработке “Менеджера паролей”

#java #android #contentprovider #android_sqlite


Какие, на Ваш взгляд, механизмы обеспечения безопасности доступа к данным необходимо
использовать при реализации контент-провайдера? А какие вовсе не обязательно, но возможно? 
Рассматривается сценарий, при котором будут иметься как приложения с предоставляемым
им ограниченным доступом(только чтение некоторой части данных), так и основное приложение-менеджер.
    


Ответы

Ответ 1



Поскольку ТС говорил о менеджере паролей, рискну сделать 2 предположения: Содержимое БД зашифровано Ключ дешифратор генерируется в момент логина юзера в программу Это общие места при создании менеджера паролей (говорю как человек написавший несколько таковых программ). Теперь обратимся к ContentProvider - они бывают либо exported либо не exported - разница между ними в том, что exported доступен внешней программе - в этом случае ContentProvider выступает как некий порт высунутый наружу программой. В зависимости от ситуации в порт можно или писать или только читать (полный перечень операций это стандартные CRUD операции). Рискну опять предположить, что раз ТС интересует способ защиты ContentProvider'а, то очевидно он хочет что провайдер был exported=true - иначе можно его сделать exported=false и забыть о проблеме. exported=true провайдер нужен в менеджере паролей, если требуется каким-то образом "проникнуть" к БД паролей в обход самой программы и получить оттуда данные (ну например просто количество записей, хэши шифров или что-то подобное относительно безвредное). Рассчитывать на ContentProvider как способ защиты данных - бессмысленно. Любые данные в Android можно получить напрямую - достаточно иметь права superuser'а. Теперь ближе к делу. Практически все пишется на уровне манифеста (ну кроме кода самого провайдера естественно), примерно так: > Здесь все более-менее понятно кроме пункта с android:sharedUserId="ru.mypackage.shared.user.id" это некая альтернатива вместо того, чтобы городить огород с ContentProvider'ом- фактически это декларация того, что доступ к данным приложения открывается для приложения с идентичным sharedUserId и совпадающей подписью - по умолчанию данные приложения в частном каталоге и закрыты для остальных приложений. Так если нужно получить доступ к данным, можно иногда обойтись и без провайдера и тупо открыть данные таким вот образом. В остальном по сути создается ваш кастомный провайдер, который защищен вашей же подписью. То есть доступ к провайдеру будет иметь только приложение обладающее пермишеном ru.mypackage.MyProvider и имеющее такую же подпись как и ваше приложение. Далее нужно иметь ввиду, что exported провайдер по сути это отдельный процесс, который запускается в момент установки приложения или в момент запуска системы и живет без вашего приложения. Соответственно, допустим такой момент, что есть обращение к провайдеру, но само приложение еще не запущено. А как мы помним речь идет о менеджере паролей то есть ключ дешифратор генерируется при входе юзера в систему. Что мы имеем? Имеем обращение к провайдеру, а ключа для дешифровки данных нет. Хорошо, если провайдеру не нужен ключ, а если нужен? Если нужен ключ необходимо запускать приложение напрямую из провайдера. В общем провайдер должен знать запущено ли приложение и если не запущено либо завершать свою работу или запускать через Intent приложение. Уфф вроде все. P.S. Я бы считал, что ContentProvider на фиг не нужен в менеджере паролей - столько гемора будет :) - достаточно обойтись sharedUserId

Ответ 2



Нашёл на китайском форуме по комп. безопасности - Drops (страница ещё доступна в кэше Гугла). Установите MinSdkVersion 9 или выше. Установите атрибут exported=false, если ContentProvider не предназначен для использования другими приложениями (похоже, не ваш случай). Используйте параметризованные запросы к БД, чтобы избежать инъекции. Если провайдером будут пользоваться другие ваши приложения для обмена данными, установите protectionLevel=“signature”, чтобы проверялась подпись. Make sure Public content provider doesn't store sensitive data. (прим.: мне не понятно, оставил без перевода) Uri.decode() перед тем, как вызвать ContentProvider.openFile(). Protect permissions when providing asset files. (прим.: тоже не понятно) Зашифруйте БД, например, с помощью SQLCipher. Если этого не сделать, злоумышленник, получивший root доступ к устройству может легко прочитать содержимое базы. Пример использования (на англ.) SQLCipher с ContentProvider.

среда, 11 декабря 2019 г.

ContentProvider и отправка одного notifyChange для группы правок данных

#android #многопоточность #contentprovider


Сделал приложение, которое использует ContentProvider и ContentObserver для работы
с данными. В ContentProvider при обновлении данных вызывается notifyChange, который,
в свою очередь, отлавливается обсервером и приводит к обновлению списка на экране.

Проблема в том, что данные у меня отправляются пачками (через contentResolver.applyBatch).
Т.е. на несколько вызовов update у провайдера мне нужно делать только одно обновление
данных на экране. 

Насколько я понимаю, на уровне ContentProvider этого не сделать (по факту applyBatch
отправляет notifyChange на каждое обновление в базе), т.к. это логика более высокого
уровня. Хотя и не уверен в этом - возможно, в ContentProvider можно как-то определять
что данная операция последняя в пачке?

Может быть кто-то с таким сталкивался и у него есть работающая схема?

Дополнение:

Обнаружил, что в ContentProvider есть метод applyBatch, который можно перекрыть.

Получился вот такой вариант с некоторой, на мой взгляд, топорной защитой (по идее,
тут надо мьютекс использовать?):

static int batchDeep = 0;

@Override
public ContentProviderResult[]applyBatch(ArrayList operations)  
                                                  throws OperationApplicationException {
    try {
        batchDeep++;
        return super.applyBatch(operations);

    } finally {
        batchDeep--;
        if (batchDeep == 0)
            getContext().getContentResolver().notifyChange(URI_INDEX, null);
    }
};


И в методах, обновляющих данные:

@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] selectionArgs) {
    ...
    if (batchDeep == 0)
        getContext().getContentResolver().notifyChange(uri, null);
    ...
}


Теоретически, этот код, вроде-бы, делает то, что нужно. Но нет-ли здесь каких-то
подводных камней, связанных с параллельным исполнением?
    


Ответы

Ответ 1



ContentProvider заботиться как раз о таких подводных камнях, что и делает его привлекательным, подробнее ContentProvider android doc.

вторник, 13 ноября 2018 г.

Применение ContentProvider при разработке “Менеджера паролей”

Какие, на Ваш взгляд, механизмы обеспечения безопасности доступа к данным необходимо использовать при реализации контент-провайдера? А какие вовсе не обязательно, но возможно? Рассматривается сценарий, при котором будут иметься как приложения с предоставляемым им ограниченным доступом(только чтение некоторой части данных), так и основное приложение-менеджер.


Ответ

Поскольку ТС говорил о менеджере паролей, рискну сделать 2 предположения:
Содержимое БД зашифровано Ключ дешифратор генерируется в момент логина юзера в программу
Это общие места при создании менеджера паролей (говорю как человек написавший несколько таковых программ).
Теперь обратимся к ContentProvider - они бывают либо exported либо не exported - разница между ними в том, что exported доступен внешней программе - в этом случае ContentProvider выступает как некий порт высунутый наружу программой. В зависимости от ситуации в порт можно или писать или только читать (полный перечень операций это стандартные CRUD операции).
Рискну опять предположить, что раз ТС интересует способ защиты ContentProvider'а, то очевидно он хочет что провайдер был exported=true - иначе можно его сделать exported=false и забыть о проблеме.
exported=true провайдер нужен в менеджере паролей, если требуется каким-то образом "проникнуть" к БД паролей в обход самой программы и получить оттуда данные (ну например просто количество записей, хэши шифров или что-то подобное относительно безвредное). Рассчитывать на ContentProvider как способ защиты данных - бессмысленно. Любые данные в Android можно получить напрямую - достаточно иметь права superuser'а.
Теперь ближе к делу. Практически все пишется на уровне манифеста (ну кроме кода самого провайдера естественно), примерно так:


>

Здесь все более-менее понятно кроме пункта с android:sharedUserId="ru.mypackage.shared.user.id" это некая альтернатива вместо того, чтобы городить огород с ContentProvider'ом- фактически это декларация того, что доступ к данным приложения открывается для приложения с идентичным sharedUserId и совпадающей подписью - по умолчанию данные приложения в частном каталоге и закрыты для остальных приложений. Так если нужно получить доступ к данным, можно иногда обойтись и без провайдера и тупо открыть данные таким вот образом.
В остальном по сути создается ваш кастомный провайдер, который защищен вашей же подписью. То есть доступ к провайдеру будет иметь только приложение обладающее пермишеном ru.mypackage.MyProvider и имеющее такую же подпись как и ваше приложение.
Далее нужно иметь ввиду, что exported провайдер по сути это отдельный процесс, который запускается в момент установки приложения или в момент запуска системы и живет без вашего приложения. Соответственно, допустим такой момент, что есть обращение к провайдеру, но само приложение еще не запущено. А как мы помним речь идет о менеджере паролей то есть ключ дешифратор генерируется при входе юзера в систему. Что мы имеем? Имеем обращение к провайдеру, а ключа для дешифровки данных нет. Хорошо, если провайдеру не нужен ключ, а если нужен? Если нужен ключ необходимо запускать приложение напрямую из провайдера.
В общем провайдер должен знать запущено ли приложение и если не запущено либо завершать свою работу или запускать через Intent приложение.
Уфф вроде все.
P.S. Я бы считал, что ContentProvider на фиг не нужен в менеджере паролей - столько гемора будет :) - достаточно обойтись sharedUserId