The pain of HTTPS
A few weeks ago we started looking into what it would take to run RavenDB 4.0 over HTTPS.
Oh, not the actual mechanics of that, we had that covered a long time ago, and pretty much everything worked as expected. No, the problem that we set out to solve was whatever we could get RavenDB to Just Work over HTTPS without requiring the admin to jump through hops. Basically, what I really wanted was a way to just spin up the server and have it running on HTTPS by default.
That turned out to be a lot harder then I wished it would be.
HTTPS has two very distinct goals:
- To encrypt communication between two parties.
- To ensure that the site you visited is actually the site you thought you visited.
The first portion can be handled by generating the certificate yourself, and the communication between client & server would be encrypted. So far so good, but the second portion is probably more important. If my communication with ThisIsNotPayPal.com is encrypted, that doesn’t really help me all that much, I’m afraid.
Verifying who you are is a very important component of HTTPS, and that is something that we can’t just ignore. Well, technically speaking I guess that RavenDB could have installed a root CA into the system during installation, but the mere thought of doing that is giving me a pause, so I really don’t want to try and do that.
And without doing that, we can’t really support HTTPS. Remember that things like Let’s Encrypt won’t work here. RavenDB is often deployed on closed networks, and without having a publicly visible domain to run. My RavenDB is running on oren-pc.hrhinos.local, for example, and I think you’ll find that it is a bit hard to get a Let’s Encrypt certificate for this.
So we can’t just magically get a certificate and have it work.
While I wish there was a way to just have encryption over the wire, without validation of identity, that would be pretty pointless with such things as man in the middle attacks.
So what do we do in RavenDB 4.0 with regards to HTTPS?
We rely on the admin (shocking, I know). They can either generate a self signed certificate and trust it ( a matter of a few shell commands on any platform ) or use their organization’s certificate (either trusted internally or externally obtained). RavenDB doesn’t care about that, but if you provide a certificate, it will ensure that all communication are SSL encrypted.
The client API exposes a method that let you control certificate validation, which make it easier if you need to customize the authentication policy. On the server side, however, we take things differently. Instead of letting the user configure trust policies in certificates, we decided to ignore the issue completely. Or, to be rather more exact, to specify that RavenDB is going to lean on the operating system for such decisions. A simple scenario is an administrator that define a cluster of servers and generate a self signed certificate(s) for them to use. The administrator need to make sure that the certificate(s) in question are trusted by all nodes in the cluster. RavenDB will refuse to connect over HTTPS to an untrusted source.
Yes, I’m aware of all the horrible things that this can do (certificate expiration kills the system, for example), but we couldn’t think of any way were not doing this wouldn’t result in even worse situations.
RavenDB has support for encrypted databases, but we don’t allow them to be accessed from non secured connection, or to connect to non secure destinations. So the data is encrypted at rest and over the wire, and the admin is responsible to making sure that the certs are up to date and valid (or at least trusted by the machines in question).
Comments
Would TLS-PSK cipher suites be an option? It's easier to manage a (list of) PSK than X509 certificates.
Chris, How would this help us in terms of being able to generate a certificate with trust?
What about outsourcing the https work to IIS, for example? Or some other tool that takes care of wrapping a TCP connection in SSL/TLS and is kind of well know to the admin population? Stunnel comes to my mind as one of the options
You could make use of self signed certificates and also make it safe as long as you mandate the server cert Thumbprint is placed in the connection string. This way man in the middle attacks are prevented. However when the cert expires connection strings will have to be updated too.
Rafal, This just move the problem a bit. It is pretty obvious we'll need to support running behind a proxy (nginx is a good example for a common deployment pattern. However, that doesn't solve any of the problems of making it easier to run over HTTPS, it just add more steps in the process. The process of generating an SSL cert that the browser will trust is the same, either you get it from an external trusted source, or you manually trust a self signed one.
Pop Catalin, That is a really interesting suggestion, and I like it very much :-)
Have you looked into using a Secure Remote Password Protocol with a Zero Knowledge proof to prove identity using knowledge of a shared secret not passed over the wire? I've had some fun with these concepts in my little MessageWire project you're welcome to look at here: https://github.com/tylerjensen/MessageWire
Tyler, That can work just fine for API access, but it would preclude using REST interfaces and the vast toolset that those have. It is also problematic given that I want to be able to serve the studio as a web app
Oren, there are no certificates involved in TLS-PSK. Both client and server need the same secret key. Simular to WPA with PSK.
Chris, How would that work with the browser?
Comment preview