Reputation: 466
I'm trying to set HTTPS SSL cipher suite preference according to server preference rather than auto select based on client & server supported common cipher suite with highest strength.
I'd like to let the server choose for common between server & client having "TLS_ECDHE..." in order to support Forward Secrecy. I've tested in "www.ssllabs.com", client browser will prefer cipher having "TLS_RSA..." rather than "TLS_ECDHE"...
I've noticed java 8 support set cipher suite preference: http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#cipher_suite_preference
I assume spring boot embedded Tomcat will call Java 8 function to choose cipher
Here is what I've done in spring boot application.properties file to set server support ciphers set:
server.ssl.ciphers=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_SHA256,TLS_ECDHE_RSA_WITH_AES_128_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_SHA,TLS_ECDHE_RSA_WITH_AES_256_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_SHA384,TLS_ECDHE_RSA_WITH_AES_256_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_SHA,TLS_DHE_RSA_WITH_AES_128_SHA256,TLS_DHE_RSA_WITH_AES_128_SHA,TLS_DHE_DSS_WITH_AES_128_SHA256,TLS_DHE_RSA_WITH_AES_256_SHA256,TLS_DHE_DSS_WITH_AES_256_SHA,TLS_DHE_RSA_WITH_AES_256_SHA
Hopefully someone can guide me how to override default choose cipher behaviour.
Upvotes: 8
Views: 21386
Reputation: 874
For Spring Boot 3.0.x with Tomcat 10.1.x this could be a solution. It's an adapted version of the original solution posted by @andy-wilkinson.
import java.util.Arrays;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CipherOrderConfig {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainerCustomizer() {
return factory ->
factory.addConnectorCustomizers(connector -> {
ProtocolHandler protocolHandler = connector.getProtocolHandler();
if (protocolHandler instanceof AbstractHttp11Protocol<?> httpHandler) {
Arrays
.stream(httpHandler.findSslHostConfigs())
.forEach(sslHostConfig -> sslHostConfig.setHonorCipherOrder(true));
}
});
}
}
It should set the cipher order honor flag to true for all configured SSL host configurations.
Upvotes: 1
Reputation: 61
Here is my solution in Spring Boot 2.3.4.RELEASE and JDK 1.8.
It works fine for me.
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HttpsConfiguration {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainerCustomizer() {
return new WebServerFactoryCustomizer<TomcatServletWebServerFactory>() {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
AbstractHttp11Protocol<?> httpHandler = ((AbstractHttp11Protocol<?>) connector.getProtocolHandler());
httpHandler.setUseServerCipherSuitesOrder(true);
httpHandler.setSSLProtocol("TLSv1.2");
httpHandler.setSSLHonorCipherOrder(true);
httpHandler.setCiphers("TLS_EMPTY_RENEGOTIATION_INFO_SCSV,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384");
}
});
}
};
}
}
Upvotes: 2
Reputation: 116171
You need to tell the connector's underlying protocol handler to use the server's cipher suite order. You can do so with a WebServerFactoryCustomizer
:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainerCustomizer() {
return (factory) -> {
factory.addConnectorCustomizers((c) ->
((AbstractHttp11Protocol<?>) c.getProtocolHandler()).setUseServerCipherSuitesOrder(true));
};
}
Upvotes: 9