java - studio - Implemente seguridad de nivel de firma en los servicios de Android con más de una firma permitida
su configuracion de seguridad ha bloqueado la ejecucion de una aplicacion formada con un certificado (2)
Estoy desarrollando una aplicación en este momento que contiene una gran cantidad de información personal del usuario, como contactos de Facebook, etc. Ahora, una de las cosas que quiero poder hacer (y he hecho, de manera bastante efectiva) Abre partes de la aplicación a aplicaciones de "terceros", utilizando el protocolo de comunicación entre procesos incorporado (AIDL) de Android. Hasta ahora tan bueno.
Aquí está el problema: debido a que estamos involucrados en el manejo de una gran cantidad de información personal, tenemos que ser muy cuidadosos sobre quién puede y quién no puede acceder a ella; específicamente, solo las aplicaciones "Confiables" deberían poder hacerlo. Entonces, la forma natural de hacer esto es usar un permiso personalizado dentro del archivo AndroidManifest.xml donde declaramos los servicios. Mi problema es este: quiero poder promulgar la protección a nivel de firma (similar al nivel de permiso de "firma" normal), pero con un poco de un retén:
No solo deseo que la solicitud se firme con nuestra firma interna para poder acceder a los servicios. Me gustaría poder crear una lista de "firmas de confianza" y en el tiempo de ejecución (o si hay una mejor manera, ¿quizás en otro momento?) Poder verificar las solicitudes entrantes en esta lista de claves de confianza.
Esto satisfaría las restricciones de seguridad de la misma manera que el nivel de permiso de "firma" normal, creo que solo los programas en la "lista de claves de confianza" podrían acceder a los servicios, y las claves son difíciles de falsificar (¿es posible? ) - pero con la ventaja adicional de que no tendríamos que firmar todas las aplicaciones que utilizan las API con la clave de nuestro equipo interno.
¿Es esto posible en este momento en Android? Y si es así, ¿hay algún requisito especial?
Gracias
Ahora he encontrado la respuesta a esta pregunta, pero la dejaré por el bien de cualquiera que busque en el futuro.
Abrí una discusión sobre android-security-discute dónde fue respondida. Enlace: http://groups.google.com/group/android-security-discuss/browse_thread/thread/e01f63c2c024a767
Respuesta corta:
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();
}
Donde Security.trustedSignatures es un Mapa del formulario:
Map<String,String>().put("public key","some description eg. name");
Coloque este método dentro de cualquier código que esté siendo llamado por el proceso externo (es decir, dentro de su interfaz). Tenga en cuenta que esto no tendrá el efecto deseado dentro del método onBind () de su Servicio Remoto.
Excelente información, pero sugeriría, en lugar de almacenar toda la cadena de la firma, almacenar / comparar el SHA-1 del certificado como se muestra en esta respuesta de matreshkin .
Esto es similar a cómo maneja Google la API de Android de Google Maps , y esto coincidirá con la salida que se muestra a través de 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();
}