Host name invalid exception

I received an invalid host name. I used this code (got it from some link) in my program. My program is working fine. My question is, is it protected enough? (since it does not check 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()); } } 
+6
source share
4 answers

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

Basically, you are trying to establish a connection without any security. If this is what you want, the solution may be "fairly safe", but most likely the answer is no.

The correct solution to this problem is to create an appropriate certificate for this domain.

Unfortunately, this is not possible if your HTTP server uses "shared hosting" (= many domain names are mapped to the same IP address). The correct solution to this problem is to get your own IP address.

If you still want to try only the Java solution, look at this answer: fooobar.com/questions/254134 / ...

+4
source

Here's a way to clear code and stay safe. I believe that the code connects to a known service (trusted). To force the Java SSL stack to accept a connection even with a host name mismatch, the best way is to add a server certificate to the JVM trust store.

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

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

 keytool -import -alias myservice -file servercertificate.cer 

Another option that I prefer to avoid regression when upgrading Java is to copy cacerts to your own place and declare it using the javax.net.ssl.trustStore system property.

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

+1
source

many times in java is used to get such exceptions

the problem may be ipconflict / ip-domain / invalid certificate mismatch

I solved this by using the appropriate IP address and installing the certificate.

+1
source

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

  • make sure you trust the certificate,
  • check the host name (if you do not know for sure that this is the only and only certificate that you trust, it is possible).

At these two points, your code does not work:

  • TrustManager that you use does not validate the certificate at all (it never throws an exception, while the API expects it to throw a CertificateException form if the certificate is not trusted).
  • The verifier of your name always returns true .

To fix your code:

  • Keep default trust managers or initialize them with their own trust store and default TrustManagerFactory .
  • Keep the default host name verifier.

The name of your question ("invalid host name exception") and your example URL https://xxx.xxx.xx.xx:8443 seem to suggest that you are connecting to an IP address.

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

If a subjectAltName extension of type dNSName is present, it MUST be used as an identifier. 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 an existing practice, obsolete and certification authorities are encouraged to use dNSName.

[...]

In some cases, the URI is indicated as an IP address rather than a host name. In this case, the subject name iPAddressAltName must be present in the certificate and must exactly match the IP in the URI.

This means that you cannot simply leave by putting the IP address in the Common Name (CN) of your Subject DN into your server certificate. If you use an IP address, it MUST be in the subjectโ€™s alternate name record. (Starting with Java 7, keytool has options for creating such certificates.)

You will find more information on which commands to use in this answer .

Speaking of which, using IP addresses can only work in the test environment itself. I donโ€™t think any commercial CA will provide you a certificate based on IP address. I would suggest setting up DNS records (even if they were only in hosts files in a test environment).

Even if you are not using an IP address, you must make sure that this certificate is valid for the host name that you are trying to contact the server with: if you have entries for the alternate subject name, one of them must match the host name; otherwise, the host name must be in the CN RDN of the subject name of this certificate.

+1
source

Source: https://habr.com/ru/post/912827/


All Articles