6

I got host name wrong exception.I have used this code(got it from some link) in my program.My program is working fine.My question is it secure enough?? (as it is not validating certificate chains)

public class Host {

    public String subscribe() throws Exception {   
        String resp = "";
        String urlString="https://xxx.xxx.xx.xx:8443/WebApplication3/NewServlet";
        URL url;
        URLConnection urlConn;
        DataOutputStream printout;
        DataInputStream input;
        String str = "";
        int flag=1;

        try {
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    System.out.println("Warning: URL Host: " + urlHostName + " vs. "
                      + session.getPeerHost());
                    return true;
                }
            };

            trustAllHttpsCertificates();
            HttpsURLConnection.setDefaultHostnameVerifier(hv);

            url = new URL(urlString);
            urlConn = url.openConnection();
            urlConn.setDoInput(true);
            Object object;
            urlConn.setUseCaches(false);

            urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            input = new DataInputStream(urlConn.getInputStream());

            while (null != ((str = input.readLine()))) {
                if (str.length() >0) {
                    str = str.trim();
                    if(!str.equals("")) {
                        //System.out.println(str);
                        resp += str;
                    }
                }
            }
            input.close();
        } catch ( MalformedURLException mue) { 
            mue.printStackTrace();
        } catch(IOException ioe) {
            ioe.printStackTrace();
        }
        return resp;
    }

    public static class miTM implements javax.net.ssl.TrustManager,
        javax.net.ssl.X509TrustManager {

        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException {
            return;
        }

        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException {
            return;
        }
    }

    private static void trustAllHttpsCertificates() throws Exception {

        //  Create a trust manager that does not validate certificate chains:
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];

        javax.net.ssl.TrustManager tm = new miTM();

        trustAllCerts[0] = tm;

        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");

        sc.init(null, trustAllCerts, null);

        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    }

}
lxbndr
  • 2,159
  • 1
  • 15
  • 17
user10101
  • 379
  • 1
  • 7
  • 18
  • 2
    Please post your code (without commented lines) as part of your question. – MByD Apr 10 '12 at 08:42
  • @Binyamin Sharet:Posted code as part of my question. – user10101 Apr 10 '12 at 08:52
  • >My question is it secure enough??< Security is usually depending on the context and the environment, it is not really measurable. In absolute, your code is not secure since you trust any certificate against any host. So if for some reason, your DNS is hacked, you could end up talking to the wrong host. – Guillaume Polet Apr 10 '12 at 08:55
  • @GuillaumePolet:I have searched on the web when I got host name error..I could find only this solution(in many links this code displayed as solution)..Is there any other solution??? – user10101 Apr 10 '12 at 09:00

4 Answers4

4

The code in miTM actually disables any SSL security checks, so the security level is pretty low (you will only get errors if the SSL certificate is broken but you don't get errors when the certificate doesn't match the domain).

Basically, you try to make a connection without any security at all. If that's what you want, the solution might be "secure enough" but most likely, the answer is "no."

The correct solution for this kind of problem is to create a matching certificate for this domain.

Unfortunately, this isn't possible when your HTTP server is using "virtual hosting" (= many domain names map to the same IP address). The correct solution for this problem is to get your own IP address.

If you still want to try a Java-only solution, have a look at this answer: https://stackoverflow.com/a/3293720/34088

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • :I have seen this link too...Actually my code belongs to the one of the link(ending with-->tutorialid=211) given in that link.SO what is the solution?? – user10101 Apr 10 '12 at 09:35
  • Get rid of the `trustAllHttpsCertificates()`. Setting the `HostnameVerifier` should be enough. – Aaron Digulla Apr 11 '12 at 07:16
  • Just commented the line trustAllHttpsCertificates(); in service method...just disabled the calling of the function is it enough?? – user10101 Apr 11 '12 at 09:17
1

Here is a way to clean up your code and to remain secure. I suppose the code connects to a known service (trusted). To make Java SSL stack accept connection even with hostname mismatch, the best way is to add the server certificate to the JVM trust store.

First you can export the server certificate from your browser and save it on disk. From Linux, you can use openssl s_client -connect xxx.xxx.xx.xx:8443 and copy/paster the server certificate in ascii-armored format to a text file.

Then import the server certificate into jre/lib/security/cacerts JKS file with keytool

keytool -import -alias myservice -file servercertificate.cer

Another option I prefer, to avoid regression when Java is updated, is to copy cacerts in your own place and declares it thanks to the javax.net.ssl.trustStore system property.

As the server certificate is in the trust store... it is trusted, until it expires. This is often used for self-signed server certificates.

Yves Martin
  • 10,217
  • 2
  • 38
  • 77
1

many times in java used to get such kind of exceptions

problem could be ipconflict/ip-domain mismatch/invalid certificate

i have solved it by using its appropriate ip address and installing certificate.

Vijay YD
  • 514
  • 1
  • 4
  • 15
1

To make the connection secure you MUST (at least):

  • verify that you trust the certificate,
  • verify the host name (unless you know for sure that this is the one and only certificate that you trust perhaps).

Your code fails on those two points:

  • The TrustManager you're using doesn't check the certificate at all (it never throws an exception, whereas the API expects it to throw a form of CertificateException when the certificate is not trusted).
  • Your hostname verifier always returns true.

To fix your code:

  • Keep the default trust managers, or initialise them with your own trust store and the default TrustManagerFactory.
  • Keep the default host name verifier.

The title of your question ("host name wrong exception") and your example URL https://xxx.xxx.xx.xx:8443 seems to suggest you're connecting to an IP address.

Unlike some browsers, Java follows the specification (RFC 2818) quite strictly on this:

If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead.

[...]

In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI.

This means that you can't just get away with putting the IP address in the Common Name (CN) of your Subject DN in your server certificate. If you're using an IP address, it MUST be in a Subject Alternative Name entry. (Starting with Java 7, keytool has options to generate such certificates.)

You will find more details about which commands to use in this answer.

This being said, using IP addresses can only really work at most in a test environment. I don't think any commercial CA will give you an IP-address based certificate. I'd suggest setting up DNS entries (even if it's just in the hosts files in a test environment).

Even if you're not using IP address, you must make sure that that certificate is valid for the host name with which you're trying to contact the server: if you have Subject Alternative Name entries, one of them must match the host name; otherwise, the host name must be in the CN RDN of the Subject DN of this certificate.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376