 |
SSL and Self Signed Certs
Posted by rbair on October 24, 2006 at 02:37 PM | Comments (9)
Connecting to web servers over https that have self signed certificates has always been a hassle in Swing applications. Hopefully, with some recently added code and API in the SwingX-WS project this is no longer the case.
I don't know about you, but I don't have the $$ to shell out for a real certificate for my own home-run webserver. That, or I'm too lazy to do it, I'm not sure which. But in either case, test servers are often setup that don't have a real SSL certificate, such as Verisign or Thawte might sell. Instead, they have self-signed certificates. Glassfish, for instance, has such a certificate. It is easy enough to enable SSL in Glassfish, but expensive to use a real certificate.
Web browsers typically don't have a problem connecting to web servers that have self-signed certs. At least, Safari doesn't complain. It simply shows a dialog indicating that the domain the browser is connecting to has a self signed cert, and asks the user whether they want to continue. Nice.
Java, on the other hand, by default won't deal with self-signed certs. Period. You also get a very unfriendly error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
It turns out, you need to write your own X509TrustManager, and this is well documented. Just such a pain that I suspect most folks simply use http and hope they don't get into trouble (or just use http since they are on internal networks).
SwingX-WS uses HttpClient behind the scenes for all work with HTTP, and as it turns out, HttpClient has support for installing new secure socket factories -- which is a good thing because I'm gonna need one of those guys in order to use my X509TrustManager. [note: An X509TrustManager can be made the default VM-wide, but you need security rights. The other approach is to install the X509TrustManager on each HttpConnection, which does not require any extra priviledges. I use this approach so I don't have problems with webstart].
Enough theory, here's the practice.:
Session s = new Session();
Response r = s.get("https://myselfsigneddomain.com");
This code sample works exactly like Safari (and I assume the other browsers). It encounters a valid self signed cert and instead of bombing with an esoteric error message, it prompts the user. Cool!
Session now sports a couple new properties that help in this process:
- sslSecurityLevel: Can be one of SecurityLevel.High, SecurityLevel.Medium, or SecurityLevel.Low. High security will act the same as Java has always acted -- simply fail if a valid certificate doesn't exist (self-signed won't work here!). Medium security is the default, and this level will prompt the user. Low security won't prompt the user if it encounters a self-signed cert, it will simply accept it. Do not use the Low security level in production applications. You will expose yourself to security vulnerabilities!
- mediumSecurityHandler: Allows you to specify a SecurityHandler. SecurityHandler is an interface with one method:
public boolean isServerSecure(String host, X509Certificate cert);. This allows you to customize the way you ask the user whether a self-signed cert should be accepted or not.
And that's it. So, go to and write a bunch of web-oriented secure Swing applications!
PS: Hopefully this all actually works :-). I've tested it, but sure has some bugs. Among which include internationalization. If anybody wants to submit patches, let me know!
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
You don't have to write your own trust manager to connect to a host with a self-signed certificate, you only need to import the certificate into your KeyStore of trust anchors. One way to do that is described in http://blogs.sun.com/andreas/entry/no_more_unable_to_find.
Posted by: andreas_s on October 24, 2006 at 10:29 PM
-
Richard--sounds great. How hard would it be to reduce the number of prompts to users to a minimum? I'm thinking about the case where we end up with multiple background threads all hitting the same self-signed server--would want to prompt the user only once, then proceed (for the rest of the application run)--also, what about caching the user's response? Firefox usually asks--this session only, forever, ...? Cheers, Patrick
Posted by: pdoubleya on October 25, 2006 at 02:25 AM
-
An extension to the first comment. If you have multiple host names that you need a trusted certificate for, you'd have to import each certificate in your truststore. Another option is to create your own root CA, and import that root CA in your application's trust store. Then you can sign as many server certificates as you want with that root CA, and they will be trusted.
Posted by: greyfairer on October 25, 2006 at 05:59 AM
-
Patrick:
Yes, that all needs to be done :-). The DefaultSecurityHandler should manage some kind of cache, and needs to also be beefed up to display the certificate and allow the user to trust this certificate one, or once for this session, or forever.
Posted by: rbair on October 25, 2006 at 10:19 AM
-
Andreas,
Yes, that is certainly possible, but what a pain! I don't expect Mom, Dad, or my brother (fellow engineer) to actually import my server's certificate just to run my application!
Posted by: rbair on October 25, 2006 at 10:21 AM
-
Richard,
the purpose of certificates is to prevent
man-in-the-middle attacks. If you silently accept any certificate or just put up a dialog that Mom or Dad will just say "yes" to without reading or understanding it, you lose that protection. In other words, you effectively have anonymous SSL that provides protection against passive attackers listening on the wire but does not protect against active attackers that modify packets.
If that satisfies your security requirements, this is a fine solution. If it is not, you should consider spending $20/year for a certificate from a commercial CA. Another option is to follow what SSH does, which is to put up a dialog the first time you connect to a new host urging the user to check the certificate. Assuming the user accepts, save the certificate permanently and check it in subsequent connection attempts. If it matches, allow connections right away. If there is a mismatch, refuse to connect without allowing the user to (easily) override. In this model, even users that just dismiss any dialogs by clicking "OK" get limited protection against active attacks in the sense that they have the assurance that they are talking to the same host each time. I consider that a much better solution.
Posted by: andreas_s on October 25, 2006 at 06:25 PM
-
Andreas:
If that satisfies your security requirements, this is a fine solution. If it is not, you should consider spending $20/year for a certificate from a commercial CA. Another option is to follow what SSH does, which is to put up a dialog the first time you connect to a new host urging the user to check the certificate. Assuming the user accepts, save the certificate permanently and check it in subsequent connection attempts. If it matches, allow connections right away. If there is a mismatch, refuse to connect without allowing the user to (easily) override. In this model, even users that just dismiss any dialogs by clicking "OK" get limited protection against active attacks in the sense that they have the assurance that they are talking to the same host each time. I consider that a much better solution.
I think this is an excellent suggestion! It at least reduces the likelyhood of a man-in-the-middle attack without sacrificing usability. Also, can you provide any links on the $20/yr SSL certificate? I found Thawte and Versign to be significantly more, and haven't really known who else is a trustworthy CA.
Thanks!
Posted by: rbair on October 26, 2006 at 08:51 AM
-
Richard, great to hear that you liked my suggestion. Regarding SSL server certificates, the cheapest CA that I am aware of with wide distribution of their root certificates in browsers and Sun's JRE is GoDaddy. It is not my place to endorse them nor have I ever tried them out, but they charge $20/year.
Posted by: andreas_s on October 26, 2006 at 04:09 PM
-
"HttpClient has support for installing new secure socket factories"
You might find commons-ssl handy for that step:
http://juliusdavies.ca/commons-ssl/
Posted by: juliusdavies on November 21, 2006 at 05:46 AM
|