Reputation: 379
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());
}
}
Upvotes: 6
Views: 3670
Reputation: 122649
To make the connection secure you MUST (at least):
Your code fails on those two points:
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).true
.To fix your code:
TrustManagerFactory
.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.
Upvotes: 1
Reputation: 534
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.
Upvotes: 1
Reputation: 10361
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.
Upvotes: 1
Reputation: 328584
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
Upvotes: 4