7

Android で非常に具体的な SSL の問題が発生しています。コードを介して特定の Web サイトにアクセスしようとすると、次のエラーが表示されます。

SSL handshake failure: Failure in SSL library, usually a protocol error
error:140773F2:SSL routines:SSL23_GET_SERVER_HELLO: sslv3 alert unexpected message (external/openssl/ssl/s23_cInt.c:500 0xaf076228:0x00000000)

ビルドに関係なくこれを取得します... API レベル 1.5、1.6、2.2、および 4.0 で試しましたが、毎回同じ結果が得られました。

いくつかのトラブルシューティングの後、ブラウザーから Web サイトにアクセスしようとしたところ、次のエラーが表示されました。

Data connectivity problem
A secure connection could not be established.

ただし、ここに問題があります... Web サイトは Windows ブラウザーで問題なく開きます (Firefox、IE、および Chrome でテスト済み)。また、奇妙なことに、Android と同じ Webkit を使用する iOS デバイスでも問題なく開きます。Web サイトは、Opera Mini ブラウザーでも問題なく動作します。

ウェブサイトはこちらです。

クライアント証明書をキーストアに追加し、無効なクライアント証明書を無視することで回避策を試みましたが、結果はありませんでした。ただし、証明書自体は問題ではないようです。

私は行き詰まっています。これを機能させる方法について誰かがガイダンスを提供できますか?

4

4 に答える 4

4

解決策を見つけました(正しい方向に向けてくれたニコライに感謝します)。

問題は 2 つあります... 1 つは Android が好まないサイト証明書を返すこと、2 つは SSLv3 のみ (TLS ではなく) が有効になっていることです。

これが私の解決策でした。まず、カスタム ソケット ファクトリ クラスを作成する必要がありました。

public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("SSLv3");

public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(truststore);

    TrustManager tm = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    sslContext.init(null, new TrustManager[] { tm }, null);
}

@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
    SSLSocket S = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    S.setEnabledProtocols(new String[] {"SSLv3"});
    return S;
}

@Override
public Socket createSocket() throws IOException {
    SSLSocket S = (SSLSocket) sslContext.getSocketFactory().createSocket();
    S.setEnabledProtocols(new String[] {"SSLv3"});
    return S;
}

}

次に、このカスタム HttpClient をコードで定義しました。

public HttpClient getNewHttpClient() {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(MySSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

3 番目に、カスタム HttpClient を呼び出して結果を解析しました。

public String test(String URIString) {
    HttpClient httpClient = getNewHttpClient();
    String result = "";
    URI uri;
    try {
        uri = new URI(URIString);
    } catch (URISyntaxException e1) {
        return "ERROR";
    }
    HttpHost host = new HttpHost(uri.getHost(), 443, uri.getScheme());
    HttpPost httppost = new HttpPost(uri.getPath());
    try {
        HttpResponse response = httpClient.execute(host, httppost);
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                    response.getEntity().getContent()
                )
            );
            String line = null;
            while ((line = reader.readLine()) != null){
              result += line + "\n";
            }

            return result;
    } catch (ClientProtocolException e) {
        return "ERROR";
    } catch (IOException e) {
        return "ERROR";
    }
}
于 2012-06-25T17:26:07.017 に答える
3

このサイトにどのようにアクセスしていますか? Android ブラウザ経由ですか?WebView? または HttpClient/HTTPSURLConnection ですか? SSL3 にのみ応答するようです。クライアントに強制的に使用させる必要があります。

于 2012-06-22T03:18:01.407 に答える
0

2日間苦労した後、この最終的な解決策がうまくいきました-

    private OkHttpClient.Builder getUnsafeOkHttpClient() {
    try {
        // Create a trust manager that does not validate certificate chains
        final TrustManager[] trustAllCerts = new X509TrustManager[]{new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }
            public X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }
        }};

        // Install the all-trusting trust manager
        final SSLContext sslContext = SSLContext.getInstance("SSL");
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        kmf.init(keyStore, "password".toCharArray());
        sslContext.init(kmf.getKeyManagers(), trustAllCerts, new java.security.SecureRandom());
        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;
            }
        });
        ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
                .allEnabledTlsVersions()
                .allEnabledCipherSuites()
                .build();
        ConnectionSpec spec1 = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT)
                .build();

        builder.connectionSpecs(Arrays.asList(spec,spec1));

        return builder;
    } catch (Exception e) {
        Logger.e("[DownloadService][getUnsafeOkHttpClient] :", false);
       return new OkHttpClient.Builder();

    }
}
于 2020-03-17T10:20:56.470 に答える
-2

これを使用して、このメソッドを呼び出します HttpsTrustManager.allowAllSSL()

それは問題を解決し、私にとってはうまく機能します。

public class HttpsTrustManager は X509TrustManager を実装します {

private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};

@Override 
public void checkClientTrusted( 
        java.security.cert.X509Certificate[] x509Certificates, String s)
        throws java.security.cert.CertificateException {

} 

@Override 
public void checkServerTrusted( 
        java.security.cert.X509Certificate[] x509Certificates, String s)
        throws java.security.cert.CertificateException {

} 

public boolean isClientTrusted(X509Certificate[] chain) {
    return true; 
} 

public boolean isServerTrusted(X509Certificate[] chain) { 
    return true; 
} 

@Override 
public X509Certificate[] getAcceptedIssuers() {
    return _AcceptedIssuers; 
} 

public static void allowAllSSL() { 
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

        @Override 
        public boolean verify(String arg0, SSLSession arg1) {
            return true; 
        } 

    }); 

    SSLContext context = null;
    if (trustManagers == null) {
        trustManagers = new TrustManager[]{new HttpsTrustManager()};
    } 

    try { 
        context = SSLContext.getInstance("TLS");
        context.init(null, trustManagers, new SecureRandom());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } 

    HttpsURLConnection.setDefaultSSLSocketFactory(context
            .getSocketFactory());
} 

}

于 2016-03-11T11:14:40.213 に答える