首页 文章

忽略Apache HttpClient 4.3中的SSL证书

提问于
浏览
88

如何忽略Apache HttpClient 4.3的SSL证书(全部信任)?

我在SO上找到的所有答案都会处理以前的版本,并且API已更改 .

有关:

编辑:

  • 仅用于测试目的 . 孩子们,不要在家里(或在 生产环境 中)尝试

14 回答

  • 5

    以下代码适用于信任自签名证书 . 创建客户端时必须使用TrustSelfSignedStrategy

    SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                builder.build());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
                sslsf).build();
    
        HttpGet httpGet = new HttpGet("https://some-server");
        CloseableHttpResponse response = httpclient.execute(httpGet);
        try {
            System.out.println(response.getStatusLine());
            HttpEntity entity = response.getEntity();
            EntityUtils.consume(entity);
        }
        finally {
            response.close();
        }
    

    我没有故意包含 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER :重点是允许使用自签名证书进行测试,这样您就不必从证书颁发机构获取适当的证书 . 您可以使用正确的主机名轻松创建自签名证书,这样做而不是添加 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER 标志 .

  • 2

    如果您使用上面的PoolingHttpClientConnectionManager过程不起作用,则忽略自定义SSLContext . 创建PoolingHttpClientConnectionManager时,必须在构造函数中传递socketFactoryRegistry .

    SSLContextBuilder builder = SSLContexts.custom();
    builder.loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            return true;
        }
    });
    SSLContext sslContext = builder.build();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslContext, new X509HostnameVerifier() {
                @Override
                public void verify(String host, SSLSocket ssl)
                        throws IOException {
                }
    
                @Override
                public void verify(String host, X509Certificate cert)
                        throws SSLException {
                }
    
                @Override
                public void verify(String host, String[] cns,
                        String[] subjectAlts) throws SSLException {
                }
    
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
    
    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
            .<ConnectionSocketFactory> create().register("https", sslsf)
            .build();
    
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
            socketFactoryRegistry);
    CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(cm).build();
    
  • 6

    作为@mavroprovato答案的补充,如果你想信任所有证书而不仅仅是自签名,那么(你的代码风格)

    builder.loadTrustMaterial(null, new TrustStrategy(){
        public boolean isTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
            return true;
        }
    });
    

    或(从我自己的代码直接复制粘贴):

    import javax.net.ssl.SSLContext;
    import org.apache.http.ssl.TrustStrategy;
    import org.apache.http.ssl.SSLContexts;
    
    // ...
    
            SSLContext sslContext = SSLContexts
                    .custom()
                    //FIXME to contain real trust store
                    .loadTrustMaterial(new TrustStrategy() {
                        @Override
                        public boolean isTrusted(X509Certificate[] chain,
                            String authType) throws CertificateException {
                            return true;
                        }
                    })
                    .build();
    

    如果你想跳过主机名验证,你需要设置

    CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
                sslsf).setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE).build();
    

    同样 . (不推荐使用ALLOW_ALL_HOSTNAME_VERIFIER) .

    强制警告:你不应该这样做,接受所有证书是一件坏事 . 但是,有一些罕见的用例需要执行此操作 .

    作为前面给出的代码的注释,即使httpclient.execute()抛出异常,您也希望关闭响应

    CloseableHttpResponse response = null;
    try {
        response = httpclient.execute(httpGet);
        System.out.println(response.getStatusLine());
        HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);
    }
    finally {
        if (response != null) {
            response.close();
        }
    }
    

    上面的代码使用了测试

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.3</version>
    </dependency>
    

    感兴趣的是,这是我的完整测试集:

    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.conn.ssl.NoopHostnameVerifier;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContextBuilder;
    import org.apache.http.ssl.TrustStrategy;
    import org.apache.http.util.EntityUtils;
    import org.junit.Test;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLHandshakeException;
    import javax.net.ssl.SSLPeerUnverifiedException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    
    public class TrustAllCertificatesTest {
        final String expiredCertSite = "https://expired.badssl.com/";
        final String selfSignedCertSite = "https://self-signed.badssl.com/";
        final String wrongHostCertSite = "https://wrong.host.badssl.com/";
    
        static final TrustStrategy trustSelfSignedStrategy = new TrustSelfSignedStrategy();
        static final TrustStrategy trustAllStrategy = new TrustStrategy(){
            public boolean isTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                return true;
            }
        };
    
        @Test
        public void testSelfSignedOnSelfSignedUsingCode() throws Exception {
            doGet(selfSignedCertSite, trustSelfSignedStrategy);
        }
        @Test(expected = SSLHandshakeException.class)
        public void testExpiredOnSelfSignedUsingCode() throws Exception {
            doGet(expiredCertSite, trustSelfSignedStrategy);
        }
        @Test(expected = SSLPeerUnverifiedException.class)
        public void testWrongHostOnSelfSignedUsingCode() throws Exception {
            doGet(wrongHostCertSite, trustSelfSignedStrategy);
        }
    
        @Test
        public void testSelfSignedOnTrustAllUsingCode() throws Exception {
            doGet(selfSignedCertSite, trustAllStrategy);
        }
        @Test
        public void testExpiredOnTrustAllUsingCode() throws Exception {
            doGet(expiredCertSite, trustAllStrategy);
        }
        @Test(expected = SSLPeerUnverifiedException.class)
        public void testWrongHostOnTrustAllUsingCode() throws Exception {
            doGet(wrongHostCertSite, trustAllStrategy);
        }
    
        @Test
        public void testSelfSignedOnAllowAllUsingCode() throws Exception {
            doGet(selfSignedCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
        }
        @Test
        public void testExpiredOnAllowAllUsingCode() throws Exception {
            doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
        }
        @Test
        public void testWrongHostOnAllowAllUsingCode() throws Exception {
            doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
        }
    
        public void doGet(String url, TrustStrategy trustStrategy, HostnameVerifier hostnameVerifier) throws Exception {
            SSLContextBuilder builder = new SSLContextBuilder();
            builder.loadTrustMaterial(trustStrategy);
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    builder.build());
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
                    sslsf).setSSLHostnameVerifier(hostnameVerifier).build();
    
            HttpGet httpGet = new HttpGet(url);
            CloseableHttpResponse response = httpclient.execute(httpGet);
            try {
                System.out.println(response.getStatusLine());
                HttpEntity entity = response.getEntity();
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        }
        public void doGet(String url, TrustStrategy trustStrategy) throws Exception {
    
            SSLContextBuilder builder = new SSLContextBuilder();
            builder.loadTrustMaterial(trustStrategy);
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    builder.build());
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
                    sslsf).build();
    
            HttpGet httpGet = new HttpGet(url);
            CloseableHttpResponse response = httpclient.execute(httpGet);
            try {
                System.out.println(response.getStatusLine());
                HttpEntity entity = response.getEntity();
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        }
    }
    

    (工作测试项目in github

  • 13

    vasekt给出的一个小补充:

    使用PoolingHttpClientConnectionManager时,提供的SocketFactoryRegistry解决方案可以正常工作 .

    但是,通过普通http的连接不再起作用 . 您还必须为http协议添加一个PlainConnectionSocketFactory,以使它们再次工作:

    Registry<ConnectionSocketFactory> socketFactoryRegistry = 
      RegistryBuilder.<ConnectionSocketFactory> create()
      .register("https", sslsf)
      .register("http", new PlainConnectionSocketFactory()).build();
    
  • 3

    尝试各种选项后,以下配置适用于http和https

    SSLContextBuilder builder = new SSLContextBuilder();
            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
    
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", new PlainConnectionSocketFactory())
                    .register("https", sslsf)
                    .build();
    
    
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
            cm.setMaxTotal(2000);//max connection
    
    
            //System.setProperty("jsse.enableSNIExtension", "false"); //""
            CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .setConnectionManager(cm)
                    .build();
    

    我使用的是http-client 4.3.3 -

    compile 'org.apache.httpcomponents:httpclient:4.3.3'

  • 1

    更简单,更短的工作代码:

    我们正在使用HTTPClient 4.3.5并且我们尝试了几乎所有解决方案都存在于stackoverflow上但没有任何问题,在思考并找出问题之后,我们来到下面的代码,它完美地工作,只需在创建HttpClient实例之前添加它 . 你用来发帖请求的一些方法......

    SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });
    
        SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(builder.build(),
                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
        HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSF).build();
        HttpPost postRequest = new HttpPost(url);
    

    继续以正常形式调用和使用HttpPost实例

  • 19

    使用http客户端4.5时,我必须使用javasx.net.ssl.HostnameVerifier来允许任何主机名(用于测试目的) . 这是我最终做的事情:

    CloseableHttpClient httpClient = null;
        try {
            SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
            sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
    
            HostnameVerifier hostnameVerifierAllowAll = new HostnameVerifier() 
                {
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                };
    
            SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(), hostnameVerifierAllowAll);
    
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(
                new AuthScope("192.168.30.34", 8443),
                new UsernamePasswordCredentials("root", "password"));
    
            httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslSocketFactory)
                .setDefaultCredentialsProvider(credsProvider)
                .build();
    
            HttpGet httpGet = new HttpGet("https://192.168.30.34:8443/axis/services/getStuff?firstResult=0&maxResults=1000");
    
            CloseableHttpResponse response = httpClient.execute(httpGet);
    
            int httpStatus = response.getStatusLine().getStatusCode();
            if (httpStatus >= 200 && httpStatus < 300) { [...]
            } else {
                throw new ClientProtocolException("Unexpected response status: " + httpStatus);
            }
    
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        finally {
            try {
                httpClient.close();
            } catch (IOException ex) {
                logger.error("Error while closing the HTTP client: ", ex);
            }
        }
    
  • 0

    这是上述技术的工作升级,相当于“curl --insecure”:

    HttpClient getInsecureHttpClient() throws GeneralSecurityException {
        TrustStrategy trustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) {
                return true;
            }
        };
    
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
    
        return HttpClients.custom()
                .setSSLSocketFactory(new SSLConnectionSocketFactory(
                        new SSLContextBuilder().loadTrustMaterial(trustStrategy).build(),
                        hostnameVerifier))
                .build();
    }
    
  • 83

    PoolingHttpClientConnectionManager 之上以及 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslFactory).build(); 如果你想使用 PoolingNHttpClientConnectionManager 的异步httpclient,代码应该类似于以下

    SSLContextBuilder builder = SSLContexts.custom();
    builder.loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            return true;
        }
    });
    SSLContext sslContext = builder.build();
    SchemeIOSessionStrategy sslioSessionStrategy = new SSLIOSessionStrategy(sslContext, 
                    new HostnameVerifier(){
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;// TODO as of now allow all hostnames
                }
            });
    Registry<SchemeIOSessionStrategy> sslioSessionRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create().register("https", sslioSessionStrategy).build();
    PoolingNHttpClientConnectionManager ncm  = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(),sslioSessionRegistry);
    CloseableHttpAsyncClient asyncHttpClient = HttpAsyncClients.custom().setConnectionManager(ncm).build();
    asyncHttpClient.start();
    
  • 27
    class ApacheHttpClient {
    
        /***
         * This is a https get request that bypasses certificate checking and hostname verifier.
         * It uses basis authentication method.
         * It is tested with Apache httpclient-4.4.
         * It dumps the contents of a https page on the console output.
         * It is very similar to http get request, but with the additional customization of
         *   - credential provider, and
         *   - SSLConnectionSocketFactory to bypass certification checking and hostname verifier.
         * @param path String
         * @param username String
         * @param password String
         * @throws IOException
         */
        public void get(String path, String username, String password) throws IOException {
            final CloseableHttpClient httpClient = HttpClients.custom()
                    .setDefaultCredentialsProvider(createCredsProvider(username, password))
                    .setSSLSocketFactory(createGenerousSSLSocketFactory())
                    .build();
    
            final CloseableHttpResponse response = httpClient.execute(new HttpGet(path));
            try {
                HttpEntity entity = response.getEntity();
                if (entity == null)
                    return;
                System.out.println(EntityUtils.toString(entity));
            } finally {
                response.close();
                httpClient.close();
            }
        }
    
        private CredentialsProvider createCredsProvider(String username, String password) {
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(
                    AuthScope.ANY,
                    new UsernamePasswordCredentials(username, password));
            return credsProvider;
        }
    
        /***
         * 
         * @return SSLConnectionSocketFactory that bypass certificate check and bypass HostnameVerifier
         */
        private SSLConnectionSocketFactory createGenerousSSLSocketFactory() {
            SSLContext sslContext;
            try {
                sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, new TrustManager[]{createGenerousTrustManager()}, new SecureRandom());
            } catch (KeyManagementException | NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
            return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        }
    
        private X509TrustManager createGenerousTrustManager() {
            return new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] cert, String s) throws CertificateException {
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] cert, String s) throws CertificateException {
                }
    
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
        }
    }
    
  • 1

    如果您使用的是 HttpClient 4.5.x ,则您的代码可能类似于以下内容:

    SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,
            TrustSelfSignedStrategy.INSTANCE).build();
    SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
            sslContext, NoopHostnameVerifier.INSTANCE);
    
    HttpClient httpClient = HttpClients.custom()
                                       .setDefaultCookieStore(new BasicCookieStore())
                                       .setSSLSocketFactory(sslSocketFactory)
                                       .build();
    
  • 5

    (我会直接在vasekt的答案中添加评论,但我没有足够的声望点(不确定那里的逻辑)

    无论如何...我想说的是,即使你没有明确地创建/要求PoolingConnection,也不意味着你没有得到它 .

    我疯狂地想弄清楚为什么原来的解决方案不适合我,但我忽略了vasekt的答案,因为它“不适用于我的情况” - 错了!

    我低时盯着我的堆栈跟踪,看到我在它的中间看到了一个PoolingConnection . 砰 - 我累了他的补充和成功! (我们的演示是明天,我变得绝望):-)

  • 2

    信任Apache HTTP客户端中的所有证书

    TrustManager[] trustAllCerts = new TrustManager[]{
                        new X509TrustManager() {
                            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                return null;
                            }
                            public void checkClientTrusted(
                                java.security.cert.X509Certificate[] certs, String authType) {
                            }
                            public void checkServerTrusted(
                                java.security.cert.X509Certificate[] certs, String authType) {
                            }
                        }
                    };
    
              try {
                    SSLContext sc = SSLContext.getInstance("SSL");
                    sc.init(null, trustAllCerts, new java.security.SecureRandom());
                    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                            sc);
                    httpclient = HttpClients.custom().setSSLSocketFactory(
                            sslsf).build();
                    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    
  • 131

    您可以使用以下代码段来获取没有ssl认证检查的HttpClient实例 .

    private HttpClient getSSLHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    
            LogLoader.serverLog.trace("In getSSLHttpClient()");
    
            SSLContext context = SSLContext.getInstance("SSL");
    
            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;
                }
            };
    
            context.init(null, new TrustManager[] { tm }, null);
    
            HttpClientBuilder builder = HttpClientBuilder.create();
            SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(context);
            builder.setSSLSocketFactory(sslConnectionFactory);
    
            PlainConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory();
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("https", sslConnectionFactory).register("http", plainConnectionSocketFactory).build();
    
            PoolingHttpClientConnectionManager ccm = new PoolingHttpClientConnectionManager(registry);
            ccm.setMaxTotal(BaseConstant.CONNECTION_POOL_SIZE);
            ccm.setDefaultMaxPerRoute(BaseConstant.CONNECTION_POOL_SIZE);
            builder.setConnectionManager((HttpClientConnectionManager) ccm);
    
            builder.disableRedirectHandling();
    
            LogLoader.serverLog.trace("Out getSSLHttpClient()");
    
            return builder.build();
        }
    

相关问题