我正在开发一个包含大量个人用户信息的应用程序 - 例如Facebook联系人等等......现在,我想要做的事情之一(并且已经完成了,非常有效地)使用Android的内置进程间通信协议(AIDL)向“第三方”应用程序开放应用程序的一部分。到目前为止一切都很好。
这里有一个问题:因为我们参与处理了大量的个人信息,所以我们必须非常小心谁能够访问它,哪些不能访问它;具体来说,只有“受信任”的应用程序才能够这样做。因此,执行此操作的自然方法是在我们声明服务的AndroidManifest.xml文件中使用自定义权限。我的问题是这样的:我希望能够实现签名级保护(类似于普通的“签名”权限级别),但有一点点:
我不只希望使用我们的内部签名签名的应用程序才能访问这些服务。我希望能够建立一个“可信签名”列表。在运行时(或者如果有更好的方法,那么可能还有其他时间?)能够根据可信密钥列表检查传入的请求。
这将以与我认为的正常“签名”权限级别相同的方式满足安全性约束 - 只有“可信密钥列表”上的程序才能访问服务,并且密钥很难欺骗(如果可能的话)完全没有?) - 但是还有额外的好处,我们不必签署每个使用我们内部团队密钥的API的应用程序。
目前在Android中这可能吗?如果是这样,有什么特殊要求吗?
由于
答案 0 :(得分: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<String,String>().put("public key","some description eg. name");
将此方法放在外部进程调用的任何代码中(即在您的界面中)。请注意,这将 not 在RemoteService的onBind()方法中具有所需的效果。
答案 1 :(得分:2)
很好的信息jelford,但我建议不要存储整个签名字符串,以存储/比较证书的SHA-1,如answer from matreshkin所示。
这与Google handles the 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();
}