通过 HTTPS 使用 HttpClient 信任所有证书 [英] Trusting all certificates using HttpClient over HTTPS

查看:76
本文介绍了通过 HTTPS 使用 HttpClient 信任所有证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近通过 Https 发布了一个关于 HttpClient 的问题(在这里找到).我已经取得了一些进展,但我遇到了新的问题.与我的上一个问题一样,我似乎无法在任何地方找到适合我的示例.基本上,我希望我的客户端接受任何证书(因为我只指向一个服务器),但我不断收到 javax.net.ssl.SSLException:不可信服务器证书异常.

这就是我所拥有的:

public void connect() 抛出 A_WHOLE_BUNCH_OF_EXCEPTIONS {HttpPost post = new HttpPost(new URI(PROD_URL));post.setEntity(new StringEntity(BODY));KeyStore 信任 = KeyStore.getInstance("BKS");信任.加载(空,".toCharArray());SSLSocketFactory sslf = 新 SSLSocketFactory(可信);sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);SchemeRegistry schemeRegistry = new SchemeRegistry();schemeRegistry.register(新方案("https", sslf, 443));SingleClientConnManager cm = new SingleClientConnManager(post.getParams(),计划注册);HttpClient 客户端 = 新的 DefaultHttpClient(cm, post.getParams());HttpResponse 结果 = client.execute(post);}

这是我得到的错误:

 W/System.err(901): javax.net.ssl.SSLException: 不受信任的服务器证书W/System.err(901):在 org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360)W/System.err(901):在 org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)W/System.err(901): 在 org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321)W/System.err(901):在 org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129)W/System.err(901):在 org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)W/System.err(901):在 org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)W/System.err(901):在 org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)W/System.err(901): 在 org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)W/System.err(901): 在 org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)W/System.err(901): 在 org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)W/System.err(901): 在 me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129)W/System.err(901): 在 me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77)W/System.err(901): 在 me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49)W/System.err(901):由:java.security.cert.CertificateException:java.security.InvalidAlgorithmParameterException:信任锚集为空W/System.err(901):在 org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157)W/System.err(901):在 org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355)W/System.err(901): ... 12 更多W/System.err(901):引起:java.security.InvalidAlgorithmParameterException:信任锚集为空W/System.err(901):在 java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645)W/System.err(901):在 java.security.cert.PKIXParameters.<init>(PKIXParameters.java:89)W/System.err(901):在 org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.<init>(TrustManagerImpl.java:89)W/System.err(901):在 org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134)W/System.err(901):在 javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err(901):在 org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263)W/System.err(901):在 org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:190)W/System.err(901):在 org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:216)W/System.err(901): 在 me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107)W/System.err(901): ... 2 更多

注意:不要在您不完全信任的网络上使用的生产代码中实现这一点.尤其是通过公共互联网传输的任何内容.

你的问题正是我想知道的.经过一番搜索,得出的结论如下.

在 HttpClient 方式中,您应该从 org.apache.http.conn.ssl.SSLSocketFactory 创建一个自定义类,而不是 org.apache.http.conn.ssl.SSLSocketFactory本身.在这篇文章中可以找到一些线索 自定义 SSL 处理停止在 Android 2.2 FroYo 上工作.

一个例子就像......

import java.io.IOException;导入 java.net.Socket;导入 java.net.UnknownHostException;导入 java.security.KeyManagementException;导入 java.security.KeyStore;导入 java.security.KeyStoreException;导入 java.security.NoSuchAlgorithmException;导入 java.security.UnrecoverableKeyException;导入 java.security.cert.CertificateException;导入 java.security.cert.X509Certificate;导入 javax.net.ssl.SSLContext;导入 javax.net.ssl.TrustManager;导入 javax.net.ssl.X509TrustManager;导入 org.apache.http.conn.ssl.SSLSocketFactory;公共类 MySSLSocketFactory 扩展了 SSLSocketFactory {SSLContext sslContext = SSLContext.getInstance("TLS");公共 MySSLSocketFactory(KeyStore truststore) 抛出 NoSuchAlgorithmException、KeyManagementException、KeyStoreException、UnrecoverableKeyException {超级(信任库);TrustManager tm = 新 X509TrustManager() {public void checkClientTrusted(X509Certificate[] chain, String authType) 抛出 CertificateException {}public void checkServerTrusted(X509Certificate[] chain, String authType) 抛出 CertificateException {}公共 X509Certificate[] getAcceptedIssuers() {返回空;}};sslContext.init(null, new TrustManager[] { tm }, null);}@覆盖public Socket createSocket(Socket socket, String host, int port, boolean autoClose) 抛出 IOException, UnknownHostException {返回 sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);}@覆盖公共套接字 createSocket() 抛出 IOException {返回 sslContext.getSocketFactory().createSocket();}}

并在创建 HttpClient 实例时使用该类.

public HttpClient getNewHttpClient() {尝试 {KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());trustStore.load(null, null);MySSLSocketFactory sf = 新的 MySSLSocketFactory(trustStore);sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);HttpParams params = new BasicHttpParams();HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);SchemeRegistry 注册表 = new SchemeRegistry();registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));registry.register(新方案(https",SF,443));ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);返回新的 DefaultHttpClient(ccm, params);} 捕获(异常 e){返回新的 DefaultHttpClient();}}

顺便说一句,下面的链接适用于正在寻找 HttpURLConnection 解决方案的人.Https连接安卓

我已经在 froyo 上测试了上述两种解决方案,在我的情况下,它们都非常有效.最后,使用 HttpURLConnection 可能会面临重定向问题,但这超出了主题.

注意:在您决定信任所有证书之前,您可能应该充分了解该站点并且不会对最终用户造成危害.

确实,你所承担的风险应该慎重考虑,包括以下评论中提到的黑客模拟站点的影响,我深表感谢.在某些情况下,虽然可能很难处理所有证书,但您最好了解信任所有证书的隐含缺点.

Recently posted a question regarding the HttpClient over Https (found here). I've made some headway, but I've run into new issues. As with my last problem, I can't seem to find an example anywhere that works for me. Basically, I want my client to accept any certificate (because I'm only ever pointing to one server) but I keep getting a javax.net.ssl.SSLException: Not trusted server certificate exception.

So this is what I have:


    public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS {

        HttpPost post = new HttpPost(new URI(PROD_URL));
        post.setEntity(new StringEntity(BODY));

        KeyStore trusted = KeyStore.getInstance("BKS");
        trusted.load(null, "".toCharArray());
        SSLSocketFactory sslf = new SSLSocketFactory(trusted);
        sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme ("https", sslf, 443));
        SingleClientConnManager cm = new SingleClientConnManager(post.getParams(),
                schemeRegistry);

        HttpClient client = new DefaultHttpClient(cm, post.getParams());
        HttpResponse result = client.execute(post);
    }

And here's the error I'm getting:

    W/System.err(  901): javax.net.ssl.SSLException: Not trusted server certificate 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360) 
    W/System.err(  901):    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321) 
    W/System.err(  901):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
    W/System.err(  901):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49) 
    W/System.err(  901): Caused by: java.security.cert.CertificateException: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355) 
    W/System.err(  901):    ... 12 more 
    W/System.err(  901): Caused by: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645) 
    W/System.err(  901):    at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.<init>(TrustManagerImpl.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134) 
    W/System.err(  901):    at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err(  901):     at org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:190) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:216) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107) 
    W/System.err(  901):    ... 2 more

解决方案

Note: Do not implement this in production code you are ever going to use on a network you do not entirely trust. Especially anything going over the public internet.

Your question is just what I want to know. After I did some searches, the conclusion is as follows.

In HttpClient way, you should create a custom class from org.apache.http.conn.ssl.SSLSocketFactory, not the one org.apache.http.conn.ssl.SSLSocketFactory itself. Some clues can be found in this post Custom SSL handling stopped working on Android 2.2 FroYo.

An example is like ...

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;
public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    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 {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

and use this class while creating instance of HttpClient.

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

        MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.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();
    }
}

BTW, the link below is for someone who is looking for HttpURLConnection solution. Https Connection Android

I have tested the above two kinds of solutions on froyo, and they all work like a charm in my cases. Finally, using HttpURLConnection may face the redirect problems, but this is beyond the topic.

Note: Before you decide to trust all certificates, you probably should know the site full well and won't be harmful of it to end-user.

Indeed, the risk you take should be considered carefully, including the effect of hacker's mock site mentioned in the following comments that I deeply appreciated. In some situation, although it might be hard to take care of all certificates, you'd better know the implicit drawbacks to trust all of them.

这篇关于通过 HTTPS 使用 HttpClient 信任所有证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆