fast - ssl pinning android
Confiando en todos los certificados con okHttp (5)
¡Nunca debes pretender anular la validación del certificado en el código! Si necesita realizar pruebas, use una CA interna / de prueba e instale el certificado raíz de CA en el dispositivo o emulador. Puede usar BurpSuite o Charles Proxy si no sabe cómo configurar una CA.
Para propósitos de prueba, estoy tratando de agregar una fábrica de socket a mi cliente okHttp que confía todo mientras se establece un proxy. Esto se ha hecho muchas veces, pero a mi implementación de una fábrica de socket confiable le falta algo:
class TrustEveryoneManager implements X509TrustManager {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}
OkHttpClient client = new OkHttpClient();
final InetAddress ipAddress = InetAddress.getByName("XX.XXX.XXX.XXX"); // some IP
client.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipAddress, 8888)));
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = new TrustManager[]{new TrustEveryoneManager()};
sslContext.init(null, trustManagers, null);
client.setSslSocketFactory(sslContext.getSocketFactory);
No se envían solicitudes desde mi aplicación y no se registran excepciones por lo que parece que está fallando silenciosamente dentro de okHttp. Tras una investigación adicional, parece que hay una excepción que se tragó en la Connection.upgradeToTls()
de okHttp Connection.upgradeToTls()
cuando se está forzando el protocolo de enlace. La excepción que se me está dando es: javax.net.ssl.SSLException: SSL handshake terminated: ssl=0x74b522b0: SSL_ERROR_ZERO_RETURN occurred. You should never see this.
javax.net.ssl.SSLException: SSL handshake terminated: ssl=0x74b522b0: SSL_ERROR_ZERO_RETURN occurred. You should never see this.
El siguiente código produce un SSLContext
que funciona como un amuleto al crear un SSLSocketFactory que no arroja ninguna excepción:
protected SSLContext getTrustingSslContext() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final SSLContextBuilder trustingSSLContextBuilder = SSLContexts.custom()
.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true; // Accepts any ssl cert whether valid or not.
}
});
return trustingSSLContextBuilder.build();
}
El problema es que estoy tratando de eliminar por completo todas las dependencias de Apache HttpClient de mi aplicación. El código subyacente con Apache HttpClient para producir SSLContext
parece bastante sencillo, pero obviamente me falta algo, ya que no puedo configurar mi SSLContext
para que coincida con esto.
¿Alguien podría producir una implementación SSLContext que hace lo que me gustaría sin usar Apache HttpClient?
El siguiente método está en desuso
sslSocketFactory(SSLSocketFactory sslSocketFactory)
Considere actualizarlo a
sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
En caso de que alguien caiga aquí, la (única) solución que funcionó para mí es crear el OkHttpClient
como se explica here .
Aquí está el código:
private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
SSLSocketFactory no expone su X509TrustManager, que es un campo que OkHttp necesita para construir una cadena de certificados limpia. Este método en su lugar debe usar la reflexión para extraer el administrador de confianza. Las aplicaciones deberían preferir llamar a sslSocketFactory (SSLSocketFactory, X509TrustManager), lo que evita dicha reflexión.
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslContext.getSocketFactory(),
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
});
actualizar okhttp3.0, la función getAcceptedIssuers () debe devolver una matriz vacía en lugar de nula