Android 安全地限制对文件提供程序的访问

Android 安全地限制对文件提供程序的访问,android,android-contentprovider,android-fileprovider,Android,Android Contentprovider,Android Fileprovider,如何创建两个Android应用程序,其中应用程序A创建文件,只有应用程序B可以读取文件?乍一看,这似乎是个诀窍,因为它允许限制对某些包的访问,例如: //grant permision for app with package "packageName", eg. before starting other app via intent context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISS

如何创建两个Android应用程序,其中应用程序A创建文件,只有应用程序B可以读取文件?乍一看,这似乎是个诀窍,因为它允许限制对某些包的访问,例如:

//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);
以上是来自

不幸的是,任何人都可以用给定的包名创建应用程序。因此,这种限制方法不是很安全


有没有更安全的方法来限制文件访问?在这种情况下,也许通过检索调用应用程序app B的公钥证书?

没有一种真正可靠的方法来完成您正在寻找的任务

grantUriPermission似乎是一种非常简单的方法。这是android系统支持的一项服务,因此它已经在那里供您使用。正如您所说,任何人都可以使用所需的软件包名称创建应用程序,但请记住,他们必须确定所需的软件包名称

另一种方法可以是普通的旧加密。此方法与上面的方法非常相似,其中加密密钥是包名。它最终会更加安全,因为查看哪个应用程序可以访问文件可能比计算加密密钥更容易

你可以调查一下。基本上,内容提供商是一种与其他应用程序共享数据库的方法,并使用代码控制对数据库的访问。当我们谈论访问文件时,我假设无论文件存储什么,数据库也可以以更整洁和隐藏的方式存储

文件提供程序具有文件请求和批准功能。文件是。这似乎不是您寻求的解决方案,因为我不确定存储的文件在存储时是否有任何保护,例如加密,仅访问控制

注意:反编译应用程序并访问其代码和资源非常简单,其中包括源代码、加密密钥、数据库登录等等。鉴于该应用程序足够复杂,需要花费大量时间对其中发生的事情进行反向工程,但只要有足够的时间,并且攻击者有足够的耐心,就可以做到这一点。因此,根本不存在没有漏洞的100%安全方法

如果有足够的时间,任何保护都可能破裂。重要的是能够确定合理的保障措施和偏执狂之间的界限。为了说明我的看法,我会选择grantUriPermission的组合,因为在卸载应用程序时,数据库会被删除,而分散在应用程序中的加密和命名奇怪的类会使反向工程变得更加困难,我知道这叫我偏执狂


祝你好运

没有一种真正可靠的方法来做你想要做的事情

grantUriPermission似乎是一种非常简单的方法。这是android系统支持的一项服务,因此它已经在那里供您使用。正如您所说,任何人都可以使用所需的软件包名称创建应用程序,但请记住,他们必须确定所需的软件包名称

另一种方法可以是普通的旧加密。此方法与上面的方法非常相似,其中加密密钥是包名。它最终会更加安全,因为查看哪个应用程序可以访问文件可能比计算加密密钥更容易

你可以调查一下。基本上,内容提供商是一种与其他应用程序共享数据库的方法,并使用代码控制对数据库的访问。当我们谈论访问文件时,我假设无论文件存储什么,数据库也可以以更整洁和隐藏的方式存储

文件提供程序具有文件请求和批准功能。文件是。这似乎不是您寻求的解决方案,因为我不确定存储的文件在存储时是否有任何保护,例如加密,仅访问控制

注意:反编译应用程序并访问其代码和资源非常简单,其中包括源代码、加密密钥、数据库登录等等。鉴于该应用程序足够复杂,需要花费大量时间对其中发生的事情进行反向工程,但只要有足够的时间,并且攻击者有足够的耐心,就可以做到这一点。因此,根本不存在没有漏洞的100%安全方法

如果有足够的时间,任何保护都可能破裂。重要的是能够确定合理的保障措施和偏执狂之间的界限。为了说明我的看法,我会选择grantUriPermission的组合,因为在卸载应用程序时,数据库会被删除,而分散在应用程序中的加密和命名奇怪的类会使反向工程变得更加困难,我知道这叫我偏执狂

祝你好运

在这种情况下,可能通过检索调用应用程序app B的公钥证书

这是绝对可能的:

  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);
  }

getSignatureHash的结果与您得到的格式相同 从JDK的keytool,您可以生成适当的散列,将其保存在某个位置,例如string资源,并将其与您动态确定的散列进行比较。然后,如果声称是B的应用程序没有正确的散列,则您不会向其发送Uri以供使用

注意,我需要更新这段代码来处理具有多个签名的APK,这是现在的事情

在这种情况下,可能通过检索调用应用程序app B的公钥证书

这是绝对可能的:

  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);
  }

getSignatureHash的结果与您从JDK的keytool获得的格式相同,因此您可以生成适当的散列,将其保存在某个位置,例如字符串资源,并将其与动态确定的散列进行比较。然后,如果声称是B的应用程序没有正确的散列,则您不会向其发送Uri以供使用


请注意,我需要更新此代码以处理具有多个签名的APK,这是现在的事情

谢谢!我没有立即看到FileProvider将在哪里接收包名。“你愿意详细说明一下吗?”布莱恩利克斯:我不明白你的问题。您知道自己的应用程序ID BuildConfig.application\u ID。要使其正常工作,您还需要知道其他应用程序的应用程序ID。你如何处理这个问题,例如,将价值烘焙到你的应用程序中,这取决于你。谢谢!我没有立即看到FileProvider将在哪里接收包名。“你愿意详细说明一下吗?”布莱恩利克斯:我不明白你的问题。您知道自己的应用程序ID BuildConfig.application\u ID。要使其正常工作,您还需要知道其他应用程序的应用程序ID。你如何处理这一点,例如,将价值烘焙到你的应用程序中取决于你。