Spring Webflux WebClient - Specify the TLS version (between TLSv1.2 and TLSv1.3) used when sending outbound request

Viewed 1195

Small question regarding the Spring WebClient from Spring Webflux, and how to configure the TLS versions when sending outbound http request (where I'm the client).

In a SpringBoot MVC project (not Webflux), I am using the Webflux Webclient (which is possible to mix the two).

I am using the client to call two external parties HTTP servers I have absolutely no control over. First service is AliceService. Alice service is configured to accept only requests that are TLSv1.2

Second service is BobService. Bob Service is configured the accept only requests that are TLSV1.3

Hence, I am currently facing an issue. I am never able to call both of them at the same time.

I tried different combinations of

-Djdk.tls.client.protocols=TLSv1.2
-Djdk.tls.client.protocols=TLSv1.3

server.ssl.enabled-protocols=TLSv1.2
server.ssl.enabled-protocols=TLSv1.3

Every time, I will either change all my outbound requests to TLSv1.2 (hence the service accepting only TLSv1.3 will fail) or change all my outbound call to TLSv1.3 (hence the service accepting only TLSv1.2 will fail).

I even have two different instances of WebClient.

May I ask how to configure which TLS version is used when sending the outbound request? How to resolve this problem please?

Thank you

2 Answers

You can create two separate web clients for this purpose. One for TLSv1.2 and one for TLSv1.3.

Here is the minimum code snippet that you can use to build your WebClient along with other configuration that you need.

WebClient for TLSv1.2

    final SslContext sslContextForTls12 = SslContextBuilder.forClient()
            .protocols("TLSv1.2")
            .build();
    
    final HttpClient httpClientForTls12 = HttpClient.create()
            .secure(ssl -> ssl.sslContext(sslContextForTls12));
            
    final WebClient webClientForTls12 = WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(httpClientForTls12))
            .build();

WebClient for TLSv1.3

    final SslContext sslContextForTls13 = SslContextBuilder.forClient()
            .protocols("TLSv1.3")
            .build();
    
    final HttpClient httpClientForTls13 = HttpClient.create()
            .secure(ssl -> ssl.sslContext(sslContextForTls13));
            
    final WebClient webClientForTls13 = WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(httpClientForTls13))
            .build();

I have tested this configuration for a website that supports various TLS versions. This answer has mentioned the list of sites that I used for testing.

This should not be hardcoded/-configured but auto negotiated during TLS handshake, based on the capabilities of server and client, otherwise it becomes a maintenance nightmare. You do not need to worry about downgrade attacks as TLS has a protection mechanism to detect that.

You should be able to see this with: -Djavax.net.debug=all or similar. See the JSSE Reference Guide, Debugging Utilities

If you want to avoid certain older versions of TLS the correct solution is to blacklist insecure old ciphers (due to security/compliance) which can be accomplished through changing: jdk.tls.disabledAlgorithms in the config file: jre/lib/security/java.security, which on up-to-date Java installations contains reasonably secure defaults.

Related