Como faço para ignorar erros de certificado SSL inválidos com o Apache HttpClient 4.0?
Você precisa criar um SSLContext com seu próprio TrustManager e criar um esquema HTTPS usando este contexto. Aqui está o código
SSLContext sslContext = SSLContext.getInstance("SSL"); // set up a TrustManager that trusts everything sslContext.init(null, new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { System.out.println("getAcceptedIssuers ============="); return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { System.out.println("checkClientTrusted ============="); } public void checkServerTrusted(X509Certificate[] certs, String authType) { System.out.println("checkServerTrusted ============="); } } }, new SecureRandom()); SSLSocketFactory sf = new SSLSocketFactory(sslContext); Scheme httpsScheme = new Scheme("https", 443, sf); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(httpsScheme); // apache HttpClient version >4.2 should use BasicClientConnectionManager ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry); HttpClient httpClient = new DefaultHttpClient(cm);
Todas as outras respostas foram descontinuadas ou não funcionaram para o HttpClient 4.3.
Aqui está uma maneira de permitir todos os nomes de host ao criar um cliente http.
HttpClientBuilder b = HttpClientBuilder.create(); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build(); b.setSslcontext( sslContext); // or SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactory) .build(); // allows multi-threaded use PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry); b.setConnectionManager( connMgr); HttpClient client = b.build();
Isso é extraído da nossa implementação real de trabalho.
As outras respostas são populares, mas para o HttpClient 4.4 elas não funcionam. Passei horas tentando e esgotando as possibilidades, mas parece que houve uma mudança e relocação extremamente importantes da API em 4.4.
Se tudo o que você quer fazer é se livrar de erros de nome de host inválidos, basta fazer:
HttpClient httpClient = new DefaultHttpClient(); SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager() .getSchemeRegistry().getScheme("https").getSocketFactory(); sf.setHostnameVerifier(new AllowAllHostnameVerifier());
Apenas tive que fazer isso com o httpclient-4.5 e parece que eles estão preterindo algumas coisas desde o 4.4, então aqui está o trecho que funciona para mim e usa a API mais recente:
final SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, (x509CertChain, authType) -> true) .build(); return HttpClientBuilder.create() .setSSLContext(sslContext) .setConnectionManager( new PoolingHttpClientConnectionManager( RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)) .build() )) .build();
Estamos usando HTTPClient 4.3.5 e tentamos quase todas as soluções existem no stackoverflow mas nada, Depois de pensar e descobrir o problema, chegamos ao seguinte código que funciona perfeitamente, basta adicioná-lo antes de criar a instância HttpClient.
algum método para chamar ao fazer solicitações de postagem ….
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);
continue seu pedido na forma normal
Foi assim que eu fiz –
Criar meu próprio MockSSLSocketFactory (class anexada abaixo)
Use-o para inicializar o DefaultHttpClient. As configurações de proxy precisam ser fornecidas se um proxy for usado.
Inicializando DefaultHTTPClient –
SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory())); schemeRegistry.register(new Scheme("https", 443, new MockSSLSocketFactory())); ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry); DefaultHttpClient httpclient = new DefaultHttpClient(cm);
Mock SSL Factory –
public class MockSSLSocketFactory extends SSLSocketFactory { public MockSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(trustStrategy, hostnameVerifier); } private static final X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() { @Override public void verify(String host, SSLSocket ssl) throws IOException { // Do nothing } @Override public void verify(String host, X509Certificate cert) throws SSLException { //Do nothing } @Override public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { //Do nothing } @Override public boolean verify(String s, SSLSession sslSession) { return true; } }; private static final TrustStrategy trustStrategy = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }; }
Se por trás de um proxy, precisa fazer isso –
HttpParams params = new BasicHttpParams(); params.setParameter(AuthPNames.PROXY_AUTH_PREF, getClientAuthPrefs()); DefaultHttpClient httpclient = new DefaultHttpClient(cm, params); httpclient.getCredentialsProvider().setCredentials( new AuthScope(proxyHost, proxyPort), new UsernamePasswordCredentials(proxyUser, proxyPass));
Com fluente 4.5.2 eu tive que fazer a seguinte modificação para fazer o trabalho.
try { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSslcontext(sc).build(); String output = Executor.newInstance(httpClient).execute(Request.Get("https://127.0.0.1:3000/something") .connectTimeout(1000) .socketTimeout(1000)).returnContent().asString(); } catch (Exception e) { }
DefaultHttpClient httpclient = new DefaultHttpClient(); SSLContext sslContext; try { sslContext = SSLContext.getInstance("SSL"); // set up a TrustManager that trusts everything try { sslContext.init(null, new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { log.debug("getAcceptedIssuers ============="); return null; } public void checkClientTrusted( X509Certificate[] certs, String authType) { log.debug("checkClientTrusted ============="); } public void checkServerTrusted( X509Certificate[] certs, String authType) { log.debug("checkServerTrusted ============="); } } }, new SecureRandom()); } catch (KeyManagementException e) { } SSLSocketFactory ssf = new SSLSocketFactory(sslContext,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = this.httpclient.getConnectionManager(); SchemeRegistry sr = ccm.getSchemeRegistry(); sr.register(new Scheme("https", 443, ssf)); } catch (Exception e) { log.error(e.getMessage(),e); }
uma versão completa para o Apache HttpClient 4.1.3 (baseado no código oleg acima, mas ainda precisava de um allow_all_hostname_verifier no meu sistema):
private static HttpClient trustEveryoneSslHttpClient() { try { SchemeRegistry registry = new SchemeRegistry(); SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() { public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException { // Oh, I am easy... return true; } }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); registry.register(new Scheme("https", 443, socketFactory)); ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry); DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams()); return client; } catch (GeneralSecurityException e) { throw new RuntimeException(e); } }
Note que estou jogando novamente todas as exceções porque, na verdade, não há muito que eu possa fazer se isso falhar em um sistema real!
Se você estiver usando a API fluente , precisará configurá-lo por meio do Executor :
final SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, (x509CertChain, authType) -> true).build(); CloseableHttpClient httpClient = HttpClients.custom() .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .setSSLContext(sslContext).build(); String result = Executor.newInstance(httpClient) .execute(Request.Get("https://localhost:8080/someapi") .connectTimeout(1000).socketTimeout(1000)) .returnContent().asString();
Se você encontrou esse problema ao usar o AmazonS3Client, que incorpora o Apache HttpClient 4.1, basta definir uma propriedade do sistema como essa para que o verificador do certificado SSL seja relaxado:
-Dcom.amazonaws.sdk.disableCertChecking = true
Malícia gerenciada
fwiw, um exemplo usando a implementação “RestEasy” do JAX-RS 2.x para construir um cliente especial “trust all” …
import java.io.IOException; import java.net.MalformedURLException; import java.security.GeneralSecurityException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import javax.ejb.Stateless; import javax.net.ssl.SSLContext; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.ssl.TrustStrategy; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.ssl.SSLContexts; @Stateless @Path("/postservice") public class PostService { private static final Logger LOG = LogManager.getLogger("PostService"); public PostService() { } @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public PostRespDTO get() throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, GeneralSecurityException { //...object passed to the POST method... PostDTO requestObject = new PostDTO(); requestObject.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C"))); requestObject.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC"))); //...build special "trust all" client to call POST method... ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(createTrustAllClient()); ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build(); ResteasyWebTarget target = client.target("https://localhost:7002/postRespWS").path("postrespservice"); Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(requestObject, MediaType.APPLICATION_JSON)); //...object returned from the POST method... PostRespDTO responseObject = response.readEntity(PostRespDTO.class); response.close(); return responseObject; } //...get special "trust all" client... private static CloseableHttpClient createTrustAllClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, TRUSTALLCERTS).useProtocol("TLS").build(); HttpClientBuilder builder = HttpClientBuilder.create(); NoopHostnameVerifier noop = new NoopHostnameVerifier(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, noop); builder.setSSLSocketFactory(sslConnectionSocketFactory); Registry registry = RegistryBuilder.create().register("https", sslConnectionSocketFactory).build(); HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry); builder.setConnectionManager(ccm); return builder.build(); } private static final TrustStrategy TRUSTALLCERTS = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }; }
Se você estiver usando o Apache httpclient 4.5.x , tente isto:
public static void main(String... args) { try (CloseableHttpClient httpclient = createAcceptSelfSignedCertificateClient()) { HttpGet httpget = new HttpGet("https://example.com"); System.out.println("Executing request " + httpget.getRequestLine()); httpclient.execute(httpget); System.out.println("----------------------------------------"); } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) { throw new RuntimeException(e); } } private static CloseableHttpClient createAcceptSelfSignedCertificateClient() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { // use the TrustSelfSignedStrategy to allow Self Signed Certificates SSLContext sslContext = SSLContextBuilder .create() .loadTrustMaterial(new TrustSelfSignedStrategy()) .build(); // we can optionally disable hostname verification. // if you don't want to further weaken the security, you don't have to include this. HostnameVerifier allowAllHosts = new NoopHostnameVerifier(); // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy // and allow all hosts verifier. SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts); // finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory return HttpClients .custom() .setSSLSocketFactory(connectionFactory) .build(); }