Trusting All Certificates Using Httpclient Over Https

Trusting all certificates using HttpClient over HTTPS

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.

Apache HTTP Client SSL how acccept all certificates for testing purposes

This code seems to have done the trick:

        String keyPassphrase = "";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("src/main/resources/sslCertificates/certificate.pfx"), keyPassphrase.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, null);

// Create a trust manager that does not validate certificate chains
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) {
}
}
};

// Install the all-trusting trust manager
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());


//This is the httpClient that you will use to send your http request
CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();

//Send the request
CloseableHttpResponse response = httpClient.execute(request);

Trusting all certificates with okHttp

Just in case anyone falls here, the (only) solution that worked for me is creating the OkHttpClient like explained here.

Here is the code:

private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}

@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};

// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});

OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Ignoring SSL certificate in Apache HttpClient 4.3

The code below works for trusting self-signed certificates. You have to use the TrustSelfSignedStrategy when creating your client:

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

I did not include the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER on purpose: The point was to allow testing with self signed certificates so you don't have to acquire a proper certificate from a certification authority. You can easily create a self-signed certificate with the correct host name, so do that instead of adding the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER flag.

Security implications of trusting all client certificates on a server (Java X509TrustManager)

I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

Requesting but not validating the client certificate does not introduce any security issues compared to not requesting a client certificate in the first place.

Using a client certificate for authentication without validating it instead obviously adds problems, since an attacker could present a self-made certificate in this case. But as you wrote, the client certificate will be (hopefully properly) checked outside of the TLS handshake later before accepting is for authentication. In this case it is perfectly safe to not check it inside the handshake.

I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

Even if certificate validation is off it will still be verified that the client owns the presented certificate, i.e. that it has the matching private key.

Is there any risk to also leaving the checkServerTrusted()/getAcceptedIssuers() methods in my TrustManager blank/null? If this TrustManager is only used by my server socket factory, will these methods ever be called?

checkServerTrusted will be called to check the server certificate, i.e. only on the client side. So this function does not matter.
I'm not sure aboutgetAcceptedIssuers - maybe it gets called when sending over the list of accepted CA to the client. It should not matter if this list is empty though.

Getting Java to accept all certs over HTTPS

You need to set the a HostNameVarifier also
Ex:

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

public class TrustAllHostNameVerifier implements HostnameVerifier {

public boolean verify(String hostname, SSLSession session) {
return true;
}

}

Then

 httpsConnection.setHostnameVerifier(new TrustAllHostNameVerifier ());

SSL in HttpClient

My question is why do we need SSL/KeyStore in this case of HttpClient 4.5.x? what do i need to do to generate a new keystore to make it work?

For your own sake you should know what trust / key material your application is supposed to use when making secure outbound connections. One does not need to generate a new keystore in order for SSL to work. One can simply use trust material shipped with the Java runtime.

Ignore self-signed certificates in Apache HTTPClient 4.5

One of the above approaches should work in case of self-signed certificates, but the weird thing is you are getting same exception in all the approaches.

I feel during SSL session establishment or handshaking protocol is not being accepted either by client or by server.

The best solution here is to debug the application.

In case of tomcat, add -Djavax.net.debug=all in setenv.sh or setenv.bat files and then restart the server.

Or you can follow this tutorial.

The OP just needed to change the port when connecting to SSL:

//For HTTPS
HttpHost httpstarget = new HttpHost("mysite.com", 443, "https");

//For HTTP
HttpHost httptarget = new HttpHost("mysite.com", 80, "http");

Allowing Untrusted SSL Certificates with HttpClient

With Windows 8.1, you can now trust invalid SSL certs. You have to either use the Windows.Web.HttpClient or if you want to use the System.Net.Http.HttpClient, you can use the message handler adapter I wrote:
http://www.nuget.org/packages/WinRtHttpClientHandler

Docs are on the GitHub:
https://github.com/onovotny/WinRtHttpClientHandler



Related Topics



Leave a reply



Submit