Android的SSL问题

我的Android上有一个非常特殊的SSL问题。 如果我尝试通过代码访问特定网站,则会出现以下错误:

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上试过了,并且每次都得到相同的结果。

经过一些故障排除后,我尝试通过浏览器访问该网站,并发现以下错误:

Data connectivity problem
A secure connection could not be established.

这是事情,尽管...网页在Windows浏览器上打开得很好(在Firefox,IE和Chrome上测试过)。 它也可以在iOS设备上使用与Android相同的webkit,这很奇怪。 Opera Mini浏览器也可以正常工作。

这是网站。

我试图通过将客户端证书添加到密钥存储区并忽略无效的客户端证书来尝试解决方法,但没有任何结果。 但是看起来证书本身不是问题。

我陷入了僵局。 任何人都可以提供任何指导我如何才能使这个工作?


你如何访问这个网站? 通过Android浏览器? 的WebView? 或者HttpClient / HTTPSURLConnection? 它似乎只响应SSL3,你必须强迫你的客户使用它。


我找到了解决方案(感谢尼古拉指引我朝着正确的方向)。

问题有两方面:一是它返回了Android不喜欢的站点证书,另外两个是仅启用了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();
    }
}

第三,我调用了自定义的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";
    }
}

使用此方法并调用此方法HttpsTrustManager.allowAllSSL()

它将解决这个问题,并为我工作得很好。

公共类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());
} 

}

链接地址: http://www.djcxy.com/p/60757.html

上一篇: SSL Issue with Android

下一篇: Fortran array memory management