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

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

问题描述

最近在Https上发布了有关 HttpClient 的问题(在这里找到)。我已经取得了一些进展,但我遇到了新的问题。和我最后一个问题一样,我似乎找不到任何适用于我的例子。基本上,我想让我的客户端接受任何证书(因为我只指向一个服务器),但我得到一个 javax.net.ssl.SSLException:不受信任的服务器证书异常



这是我所拥有的:

  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);
}

这里是我得到的错误:

  W / System.err(901):javax.net.ssl.SSLException:不受信任的服务器证书
W / System.err :at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360)
W / System.err(901):at org.apache.http.conn.ssl.AbstractVerifier。验证(AbstractVerifier.java:92)
W / System.err(901):在org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321)
W /系统。 err(901):at 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):at 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):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:信任锚集合为空
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):。 ..更多
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):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):在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):在org.apache.http。 < init>(SSLSocketFactory.java:190)
W / System.err(901):at 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 more


解决方案

在生产代码中实现这一点,你将在你不完全信任的网络上使用它。特别是在公共互联网上的任何东西。



您的问题就是我想知道的。在我做了一些搜索之后,结果如下。



在HttpClient方法中,您应该从org.apache.http.conn.ssl.SSLSocketFactory创建一个自定义类,不是一个org.apache.http.conn.ssl.SSLSocketFactory
本身。在此信息中可以找到一些线索自定义SSL处理已停止正在使用Android 2.2 FroYo



一个例子是...

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

并在创建HttpClient实例时使用此类。 / p>

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

用于HttpURLConnection解决方案。
Https Connection Android



我已经测试了上述两种解决方案在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.

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

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