2017-02-22 23 views
1

Как создать два приложения для Android, где приложение «A» создает файлы, и только приложение «B» может читать файлы? На первый взгляд, Context.grantUriPermission кажется, трюк, потому что позволяет ограничить доступ к определенным пакетам вроде так:Безопасное ограничение доступа к FileProvider

//grant permision for app with package "packageName", eg. before starting other app via intent 
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); 

(выше от «How to use support FileProvider for sharing content to other apps?»)

К сожалению, любой человек может создать приложение с заданной имя пакета. Поэтому этот метод ограничения не очень безопасен.

Есть ли более безопасный способ ограничения доступа к файлу? Возможно, путем получения сертификата открытого ключа вызывающего приложения (приложение «В» в этом случае)?

ответ

2

Существует не по-настоящему надежный способ делать то, что вы ищете.

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

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

  3. Вы можете посмотреть content providers. В основном, контент-провайдеры - это метод обмена вашей базой данных с другими приложениями и использование кода для контроля доступа к нему. Хотя мы говорим о доступе к файлу, я предполагаю, что все файлы хранятся, база данных также может хранить более аккуратным и скрытым способом.

  4. FileProvider имеет функцию запроса и утверждения файла. Документация: here. Это не похоже на решение, которое вы ищете, потому что я не уверен, что сохраненный файл вообще защищен при хранении (например, шифрование), только контроль доступа.

Примите к сведению: это удивительно просто декомпилировать приложение и получить доступ к его кода и ресурсов, среди них является исходным кодом, ключ шифрования, Логин базы данных и многое другое. Учитывая, что приложение достаточно сложное, потребуется много времени, чтобы перестроить то, что там происходит, но, учитывая достаточно времени, и злоумышленника с достаточным терпением, это можно сделать. Из-за этого 100% -ный безопасный метод без каких-либо уязвимостей просто не существует.

При наличии достаточного количества времени любая защита может быть взломана. Важно уметь определять линию между разумными гарантиями и паранойей. Чтобы дать мне это, я пошел бы за комбинацией grantUriPermission, из-за того, что после удаления базы данных приложения удаляется и шифрование, которое разбросано по всему приложению и нечетным образом названным классам, чтобы сделать сложным обратное проектирование (Назовите меня параноидальным, я знаю).

Удачи вам!

2

Возможно, путем получения сертификата открытого ключа вызывающего приложения (приложение «В» в этом случае)?

Это, безусловно, возможно:

public static String getSignatureHash(Context ctxt, String packageName)                  
    throws NameNotFoundException, NoSuchAlgorithmException { 
    MessageDigest md=MessageDigest.getInstance("SHA-256"); 
    Signature sig= 
     ctxt.getPackageManager() 
      .getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures[0]; 

    return(toHexStringWithColons(md.digest(sig.toByteArray()))); 
    } 

    // based on https://stackoverflow.com/a/2197650/115145 

    public static String toHexStringWithColons(byte[] bytes) { 
    char[] hexArray= 
     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 
      'C', 'D', 'E', 'F' }; 
    char[] hexChars=new char[(bytes.length * 3) - 1]; 
    int v; 

    for (int j=0; j < bytes.length; j++) { 
     v=bytes[j] & 0xFF; 
     hexChars[j * 3]=hexArray[v/16]; 
     hexChars[j * 3 + 1]=hexArray[v % 16]; 

     if (j < bytes.length - 1) { 
     hexChars[j * 3 + 2]=':'; 
     } 
    } 

    return new String(hexChars); 
    } 

(от my SignatureUtils class)

Результат getSignatureHash() тот же формат, что вы получите от JDK-х keytool, так что вы можете создать соответствующий хэш, сохранить его где-нибудь (например, ресурс строки) и сравнить его с тем, который вы определяете на лету. Затем, если приложение, заявляющее, что оно B, не имеет надлежащего хэша, вы не отправляете его Uri для использования.

(обратите внимание, что мне нужно обновить этот код, чтобы иметь дело с APK, с несколькими подписями, что является вещь сейчас)

+0

Спасибо за это! Я не вижу сразу, когда FileProvider получит имя пакета. Не могли бы вы немного разобраться? –

+0

@BrianRisk: Я не понимаю ваш вопрос. Вы знаете свой собственный идентификатор приложения ('BuildConfig.APPLICATION_ID'). Для этого вам также нужно знать идентификатор приложения другого приложения. Как вы справляетесь с этим (например, испечь значение в своем приложении) зависит от вас. – CommonsWare

 Смежные вопросы

  • Нет связанных вопросов^_^