The Java driver, by default, specifies two "allowed" cipher suites: TLS_RSA_WITH_AES_128_CBC_SHA & TLS_RSA_WITH_AES_256_CBC_SHA
I assume this was done to match the server defaults but causes difficulties. The client default should be to not specify any cipher suites, present all of his eligible ciphers to the server during the TLS handshake, and allow the server to narrow the choices (i.e. keep the control in the server). Basically right now if you are using TLS and want to move the server to other, stronger ciphers, you have to impact every client that connects. There is almost no valid situation where I can imagine the client wanting to specify ciphers.
Similarly, if you do want to change client ciphers, the SSLOptions constructor forces you to also supply a SSLContext which is unnecessary and may be confusing for many users. An additional constructor should be added to support supplying only the ciphers.
Quick pseudo of the change -
// In SSLOptions
remove DEFAULT_SSL_CIPHER_SUITES // no longer needed
String cipherSuites = null; // default to null
public SSLOptions(String cipherSuites) // new constructor
// In Connection.PipelineFactory
I think we're addressing the same problem from different sides. Basically I'm saying the server (99.9% of the time) has the responsibility of restricting the cipher suites - matching those on the client side is just extraneous.
For example, if a client connects with no restrictions, it's going to present its list of supported ciphers during the ClientHello phase of the TLS handshake. So something like the following -
... and lots more ...
The server is going to receive this list, compare it to its list, and pick one where they match. So since the server only supports TLS_RSA_WITH_AES_128_CBC_SHA & TLS_RSA_WITH_AES_256_CBC_SHA, it's going to select TLS_RSA_WITH_AES_128_CBC_SHA and internally you end up with something like this in the ServerHello phase -
%% Initialized: Session-1, TLS_RSA_WITH_AES_128_CBC_SHA
This shows that restricting the suites on the client side generally doesn't serve a purpose (you get the same result) and it makes the driver less flexible when someone does (like me) wants to change the ciphers to something stronger.
The only place where I can imagine wanting a whitelist (which is really what this is) on the client side is the situation where you're connecting to and/or discovering unknown clusters and want to enforce some level of strength in the cipher. I have to imagine that's the 0.1% use case though and shouldn't be the default position of the driver.
To tangent some, a feature that might be useful is a blacklist for the client. Someplace where I can list ciphers I don't wish to support. Even there though, the server is going to be the better, long-term place to enforce that.
Thanks for elaborating. I think I agree with your reasoning now. I do notice that none of the other datastax drivers behave in this way, so at the very least this would keep things consistent. The user can also control this at a JDK level, so it doesn't seem incredibly useful to have this here (although it doesn't hurt unless you are going beyond the cassandra default ciphers). In the general case, I don't think users will be using another cipher suite which was why I was originally against making the change, but I agree with your point about it not providing much value in the general case and making it needlessly more difficult if you want to adjust your supported cipher suites on the server end. I do think we should allow users to still configure a whitelist, but by default I agree we should fall back on whatever the JDK security policies allow.
No problem. I hadn't had a chance to look at the other drivers yet - assumed they behaved the same way. I'm glad to hear they don't.
I'm not sure about users not wanting another cipher suite. It's what started me down this path. And the community as a whole definitely seems to be working away from certificates with SHA-1 signatures and the TLS 1.0 suites in general. I'm pretty sure recent Chrome and Firefox installs will actively warn on (if not refuse) the TLS_RSA_WITH_AES_128_CBC_SHA suite (possibly the 256 as well). There are a number of CBC based attacks that have been demonstrated.
On the bright side, apparently the documentation and cassandra.yaml files for Cassandra are out of date since if you look at the code, at least for the 2.0.14 source I'm looking at, has the following as defaults -
So that's a little better. The ordering should be reversed but better.
But it will be great if we can get this all fixed up. Will make a lot of things easier - and hopefully more secure - in the future.
I also agree with the reasoning. We have a ticket to refactor SSLOptions before 3.0 goes GA (), I'll keep cipher suites in mind.
I've added my thoughts on the way cipher suites are handled on the server in CASSANDRA-10508. Basically my opinion on this is that cipher settings should be dealt with at JVM level. Adding code to make the JVMs default behavior more secure will potentially introduce new security bugs and needs to be regularly reviewed. It will probably cause more harm than good if there aren't really strong reasons for e.g. using custom cipher suites for the driver.