24

我目前正在开发一个包含大量个人用户信息的应用程序——比如 Facebook 联系人等……现在,我想做的一件事(并且已经完成,非常有效)使用 Android 的内置进程间通信协议 (AIDL) 向“第 3 方”应用程序开放部分应用程序。到现在为止还挺好。

问题是:因为我们涉及处理大量个人信息,所以我们必须非常小心谁可以访问它,谁不能访问它;具体来说,只有“受信任”的应用程序才能这样做。因此,执行此操作的自然方法是在我们声明服务的 AndroidManifest.xml 文件中使用自定义权限。我的问题是:我希望能够制定签名级别的保护(类似于正常的“签名”权限级别),但有一点问题:

不仅希望使用我们的内部签名签名的应用程序能够访问这些服务。我希望能够在运行时建立一个“可信签名”列表(或者如果有更好的方法,那么也许其他时间?)能够根据这个可信密钥列表检查传入的请求。

这将以与我认为的正常“签名”权限级别相同的方式满足安全约束 - 只有“受信任的密钥列表”上的程序才能访问服务,并且密钥很难被欺骗(如果可能的话? ) - 但额外的好处是,我们不必使用我们内部团队的密钥签署每个使用 API 的应用程序。

目前在Android中这可能吗?如果有,有什么特殊要求吗?

谢谢

4

2 回答 2

18

我现在已经找到了这个问题的答案,但为了以后的任何人,我会留下它。

我在 android-security-discuss 上展开了讨论,并在哪里得到了答案。链接:http ://groups.google.com/group/android-security-discuss/browse_thread/thread/e01f63c2c024a767

简短的回答:

    private boolean checkAuthorised(){
        PackageManager pm = getPackageManager();
        try {
            for (Signature sig :
                pm.getPackageInfo(pm.getNameForUid(getCallingUid()),
                        PackageManager.GET_SIGNATURES).signatures){
                LogUtils.logD("Signature: " + sig.toCharsString());
                if (Security.trustedSignatures.get(sig.toCharsString()) != null) {
                    return true;
                }
            }
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        LogUtils.logD("Couldn't find signature in list of trusted keys! Possibilities:");
        for(String sigString : Security.trustedSignatures.keySet()){
            LogUtils.logD(sigString);
        }

        /* Crash the calling application if it doesn't catch */
        throw new SecurityException();

    }

其中 Security.trustedSignatures 是以下形式的 Map:

Map<String,String>().put("public key","some description eg. name");

将此方法放在由外部进程调用的任何代码中(即在您的界面中)。请注意,这不会在 RemoteService 的 onBind() 方法中产生预期的效果。

于 2010-09-29T20:04:47.057 回答
2

很棒的信息 jelford,但我建议不要存储整个签名字符串,而是存储/比较证书的 SHA-1,如matreshkin 的这个答案所示。

这类似于Google 处理 Maps Android API的方式,这将匹配通过 keytool 显示的输出。

private boolean checkAuthorized() throws SecurityException {
    PackageManager pm = getPackageManager();
    try {
        PackageInfo packageInfo = pm.getPackageInfo(pm.getNameForUid(getCallingUid()),
            PackageManager.GET_SIGNATURES);
        Signature[] signatures = packageInfo.signatures;
        byte[] certBytes = signatures[0].toByteArray();
        CertificateFactory cf = CertificateFactory.getInstance("X509");
        X509Certificate cert = (X509Certificate)cf.generateCertificate(
            new ByteArrayInputStream(certBytes));
        MessageDigest md = MessageDigest.getInstance("SHA1");
        byte[] encodedCert = md.digest(cert.getEncoded());
        String hexString = byte2HexFormatted(encodedCert);

        Log.d("public certificate SHA-1: " + hexString);

        String trustedAppName = trustedCerts.get(hexString);
        if (trustedAppName != null) {
            Log.d("Found public certificate SHA-1 for " + trustedAppName);
            return true;
        }
    } catch (Exception e) {
        Log.e(e, "Unable to get certificate from client");
    }

    Log.w("Couldn't find signature in list of trusted certs!");
    /* Crash the calling application if it doesn't catch */
    throw new SecurityException();
}

public static String byte2HexFormatted(byte[] arr) {
    StringBuilder str = new StringBuilder(arr.length * 2);
    for (int i = 0; i < arr.length; i++) {
        String h = Integer.toHexString(arr[i]);
        int l = h.length();
        if (l == 1) h = "0" + h;
        if (l > 2) h = h.substring(l - 2, l);
        str.append(h.toUpperCase());
        if (i < (arr.length - 1)) str.append(':');
    }
    return str.toString();
}
于 2015-02-12T09:45:51.173 回答