クライアントでRetrofitを使用してHTTPS
でJSON
のデータを取得するアプリケーションをビルドしています。 KitKatでうまく動作します。 Android 5,6,7に移行すると、SSL
ハンドシェイクが失敗します。更新:API21 +デバイスで起動したときにAndroidアプリがSSLハンドシェイクに失敗する
サーバーはTLSv1
と他には何をサポートしています。また、期限切れの古い自己署名証明書も使用します。 QualysのSSLツールでテストしたところ、すべてのバージョンのAndroidが接続できるはずだと教えてくれました。
OkHttpクライアントを::
public class HTTPClient {
public 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) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create a ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//URL url = new URL(ApiIntentService.getHostAddress());
//final SSLSocketFactory sslSocketFactory = new NoSSLv3SocketFactory(url);
// ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
// .tlsVersions(TlsVersion.TLS_1_0)
// .cipherSuites(
// CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
// CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
// CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
// CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
// CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
// CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
// CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
// CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
// CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
// CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
// .build();
// String hostname = "api.server.domain";
// CertificatePinner certificatePinner = new CertificatePinner.Builder()
// .add(hostname, "sha256/3Iiwgs3a0qjPCnBQzW/GeHhPbZvhaJtxKvMJJVO5KdU=")
// .build();
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
// builder.connectionSpecs(Collections.singletonList(spec));
// builder.certificatePinner(certificatePinner);
builder.sslSocketFactory(sslSocketFactory);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
builder.authenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("user", "pass");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
私はひどく、このコードは、セキュリティの観点から解体方法を承知していますここで私が持っているものです。私の監督はそれをそうするように要求し、私は彼にその悪いことを知らせました。
私は自分の問題を解決するために2つのことを試みましたが、コードのピースでコメントアウトされています。具体的にはTLSv1
を暗号のリストとともに要求しています。他の質問でその2つを見つけましたが、何も変更しませんでした(スタックトレースはまったく同じです)。ここで
スタックトレースは、スタックトレースの興味深いビットです:
I/RETROFIT: Data retrieval failed! javax.net.ssl.SSLHandshakeException: Handshake failed
*snip*
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb43eb200: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:770 0xac6fedd4:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
AndroidはSSLv3
突然のすべてを使用しようとしますが、WiresharkのはTLSv1
を介して通信を示しているかのように見えます。 Client Hello
で始まりますが、サーバーはすぐにHandshake Failure (40)
で応答します。
私はすべてのアイデアのうち、だので、すべてのヘルプは大幅に、appreaciatedされます。それが必要な場合は、明確に尋ねてください。
ありがとうございます。
を、あなたははい、私が持っている代わりにConnectionSpec.COMPATIBLE_TLS' –
'の' ConnectionSpec.MODERN_TLS'と 'コメントアウトConnectionSpec'ピースを試してみました。それはもともとそこにあった、私はそれをドキュメントを読んで変更しました。しかし、効果はありません。 –