Disable TLS <1.2 with Spring Boot (embedded Tomcat Server) + Heroku - spring-boot

I'm trying to disable TLS <1.2 (so disable TLS 1.0 & 1.1) on my Spring boot (v. 1.4) app which is running on Heroku.
This app integrates with Salesforce so for security reasons the app (which is an outside website) should not accept TLS connections that are <1.2.
Since the Spring Boot version is 1.4, it really should be as simple as adding a few lines of code to the application.properties file OR the yaml. And, I have tried this in almost every combination.
For example, I currently have the following in my yaml:
Spring:
server:
ssl:
enabled: true
protocol: TLS
enabled-Protocols: [TLSv1.2]
The application builds fine on Heroku and is up and running, but it still accepts TLS 1.0 and 1.1 connections (confirmed via https://www.cdn77.com/tls-test), and I really do not understand why.
I'm trying to determine if this is something related to Heroku. They do manage certificates automatically via what they call ACM. And with ACM you are not able to disable certain versions of TLS. But, my understanding would be that it shouldn't matter, if I'm telling the embedded Tomcat (Spring Boot) server to only accept TLS 1.2 connections, then the Heroku server should actually come after that and hence follow the same rules.
Just to add all of the information I have: server.error.whitelabel.enabled = false is in the application.properties file. This is the only server setting in that file, but I'm just adding in case maybe applications.properties file could interfere with the yaml? (even though I have tried removing it and it did not fix the issue).
So, why is my app / website still accepting TLS <1.2 connections??
Any insight on this would be greatly appreciated!

Related

Spring Boot & reactor-netty https multiple domains

I'm trying to configure a spring cloud gateway, (on top of project Reactor) to serve HTTPS across two domains.
However it appears that it is unable to use SNI to choose the correct certificate to show to the client.
My configuration is as follows:
I've generated two different private key/ certs and both of those are stored in keystore.jks
both of them have different CommonNames and they also have Subject Alternative Names that match the expected domains.
I've entered the common name into my hosts files. To fool browser/curl into thinking that its two seperate domains.
I've configured application.yml as follows
server:
ssl:
enabled: true
# The entire purpose of this project is so that client authentication is needed
client-auth: need
---
spring:
profiles: development
server:
ssl:
key-store: config/keystore.jks
trust-store: config/truststore.jks
The purpose of this is to enable 2 way ssl authentication with two different clients both of whom issue us with their own certificates.
I know netty which is the foundation for spring cloud gateway supports SNI. Is there any way to configure SNI for spring cloud gateway?
It looks like there is an outstanding issue to Support SNI.
https://github.com/spring-cloud/spring-cloud-gateway/issues/1525 which though closed is closed by the issue creator. Not by the framework creators.
This issue links to another issue in reactor.
https://github.com/reactor/reactor-netty/issues/573
Which at the time of writing is not closed.

SpringBoot - Reload SSL Cert using Spring Cloud Config

I'm learning about using SSL Certificates with Spring Boot. Specially using Let's Encrypt ones.
They have the limitation of being expired after 3 months, so they should be renewed and as far as I know, when renewing the certificate we need to restart the Spring Boot app in order to make it load the new one instead.
Some time ago, I was playing around with Eureka and Zuul Gateway, to develop microservices... And I recall I also set a git repo to be used as a Spring Cloud Config. I do not remember well, I think we can use Spring Cloud Config without using the microservice arch.
So my question is: Can we use this Spring Cloud Config mechanism that reload properties to reload the SSL Certificate? The idea would be to trigger the properties reloading mechanism, and as the ssl is configured via those properties, I think maybe it can be reloaded.
I'm planning on automating the process of getting and renewing the Let's Encrypt certificate and avoid the downtime on my app.
Best regards!
SSL certs are applied at the JVM level - neither Spring Boot nor Spring Cloud Config has any control over this, and so to apply a new cert would require a restart of the JVM instance your app runs in, because you've updated your keystore. Being able to dynamically add certs without shutting down the JVM would be a major security flaw.
In the AWS ecosystem, the idea is that if you ever shut down your VM, you lose that VM, and the contents on it are gone forever. With Spring Cloud (Config, Zuul, Eureka) you can spin up VMs that get registered with Eureka via Config, and Zuul uses the info in Eureka to do the load balancing. So, the way it should be done is you spin up another VM with your Spring Boot instance with the updated cert, and kill off the older VM which evaporates thanks to AWS, and Zuul takes care of the dirty work of being a "reverse web proxy", routing the requests to the new web server as required.
The can of worms you open going this route is that now you have to implement 4 servers and a VPN to support them, your Zuul server becomes the target of external web requests, and you might need to look into the "circuit breaker" pattern on how to handle HTTP request failures - Hystrix is the next thing to look into.
With Digital Ocean, I'm not sure what you might have to do differently, but a JVM restart is unavoidable.
Actually, it depends. Certificates are applied on SSLContext level and SSLContext can be refreshed during runtime. It is completely possible to update the certificate in KeyStore and refresh the SSLContext, moreover, Tomcat has a special helper function reloadSslHostConfigs that helps you to do that.
So what you ask is completely doable:
Spring Cloud triggers certificate update event notification or via polling
Your application loads updated certificate either from Spring-Cloud or from some shared storage
Your application issues reloadSslHostConfigs, so that Tomcat updates its SSLContext
For implementation details of the certificate reloading, you can take a look at the letsencrypt-helper library. It allows generating and keeping-up fresh your LetsEncrypt certificate without JVM restart.

How does Spring Boot http2 handle browser requests that do not support http2 at the same time?

Spring Boot can support http/2 now, but if browser does not support http/2, can browser request server use http1.x+ssl with the same http port? Nginx can automatically downgrade http/2 to http1.x+ssl when browser does not support http/2.
Is this a Spring Boot issue, or a servlet container issue(tomcat, jetty, Undertow)?
I tried local with a Spring Boot application with http/2, browsers that support http/2 can access successfully, but access from browsers that does not support http/2 got a 'Aborted' http status.
Application informations:
Spring Boot Version: 2.1.0.M4
Servlet Container: default, Apache Tomcat/9.0.12
application.properties:
spring.application.name=spring-test
server.port=8443
server.http2.enabled=true
server.ssl.key-store=classpath:testkeystore.jks
server.ssl.key-store-password=test
server.ssl.key-password=test
Browser support http/2: Chrome, version: 66.0.3359.139
Browser does not support http/2: Firefox, version: 30.0
This is more of a container problem - although depending on the concrete problem, Spring Boot might be able to help in the way it's configuring the server.
The core issue with what you're describing is: if a server supports both http/2 and http/1.1, it still has to enforce strict minimal requirements for cipher suites, otherwise attackers could be able to force the clients to downgrade the security and use a broken cipher.
So effectively, the category of HTTP clients you're worried about is getting smaller by the day. Clients that support those modern ciphers also support http/2. For example, in the latest Jetty release, all TLS_RSA ciphers are now excluded by default.

securing spring boot app with mTLS - running on Swisscom App Cloud

I have a spring boot app deployed to Swisscom App Cloud that should to be secured with mTLS.
Obviously there's spring security... Specific to Swisscom App Cloud I read about securing traffic on https://docs.developer.swisscom.com/adminguide/securing-traffic.html.
It is unclear to me how the two play together...
If I enable mTLS via spring security, would that work as is or would I need additional configuration for the Swisscom App Cloud? (I came across HTTP routing which mentions passing client certificates for mTLS https://docs.developer.swisscom.com/concepts/http-routing.html)
Is the configuration of mTLS on Swisscom App Cloud a replacement for what I would otherwise enable with spring security or would I still need to configure something within my application?
Securing traffic mentions deployment manifest and BOSH manifest, is the latter (and maybe additional) configuration needed to enable mTLS on Swisscom App Cloud (i.e. would I need to have access to configs besides the deployment manifest) ?
Update
My use case that I have a REST API that will be consumed by a client outside of Swisscom App Cloud. It was decided that it shall be secured using mTLS.
The admin guide you're referring to is meant for platform operators (i.e. Swisscom), so it's not a resource that can be leveraged by end users.
What is your use case? If it's only a security requirement to check off a list, be aware that the platform itself will be using mTLS internally soon, so the whole path up until the app container is secured. That might be enough for your auditor.
If you really need to validate client certificates by yourself, CF's way of doing so is leveraging X-Forwarded-Client-Cert (https://docs.cloudfoundry.org/concepts/http-routing.html#-forward-client-certificate-to-applications).
However, we've currently not enabled this (there was no need for it up until now), but we can do so.
Update:
According to this explanation, insertion of X-Forwarded-Client-Cert is actually done transparently by the platform. So if you add the client application's certificate to the server application's truststore, it will verify the client certificate.
Update 2:
As you can see in the discussions below, it looks like there is currently conceptually no easy way to allow apps to do proper mTLS using X-Forwarded-Client-Cert. The only option currently is using tcp routes, which is something you can request with your Appcloud support team.

How to configure client certificates in Jetty + Spring

We are using a Jetty server along with Spring security framework. The server should accept requests from only from a known client (Which is also a server). We want to configure client certificates so that Jetty accepts only the requests with the known client certificate.
How can we configure the server?
All we need to do is set NeedClientAuth in jetty-ssl-config.xml to true. No change is needed in Spring config.

Resources