HSTS
Http4s provides a Middleware giving support for HTTP Strict Transport Security (HSTS).
The middleware is called HSTS
and simply adds a header to enable a HSTS security policy.
Though it is not enforced, HSTS only makes sense for an https
service.
Examples in this document have the following dependencies.
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-dsl" % http4sVersion,
"org.http4s" %% "http4s-server" % http4sVersion
)
And we need some imports.
import org.http4s._
import org.http4s.dsl._
Let’s make a simple service that will be exposed and wrapped with HSTS.
val service = HttpService {
case _ =>
Ok("ok")
}
// service: org.http4s.HttpService = Kleisli(org.http4s.package$HttpService$$$Lambda$30492/1993666796@7d7e7071)
val request = Request(Method.GET, uri("/"))
// request: org.http4s.Request = Request(method=GET, uri=/, headers=Headers())
// Do not call 'unsafeRun' in your code
val response = service.orNotFound(request).unsafeRun
// response: org.http4s.Response = Response(status=200, headers=Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 2))
response.headers
// res1: org.http4s.Headers = Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 2)
If we were to wrap this on the HSTS
middleware.
import org.http4s.server.middleware._
// import org.http4s.server.middleware._
val hstsService = HSTS(service)
// hstsService: org.http4s.HttpService = Kleisli(org.http4s.server.middleware.HSTS$$$Lambda$30595/1900062101@7f8192a3)
// Do not call 'unsafeRun' in your code
val response = hstsService.orNotFound(request).unsafeRun
// response: org.http4s.Response = Response(status=200, headers=Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 2, Strict-Transport-Security: max-age=31536000; includeSubDomains))
response.headers
// res3: org.http4s.Headers = Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 2, Strict-Transport-Security: max-age=31536000; includeSubDomains)
Now the response has the Strict-Transport-Security
header which will mandate browsers
supporting HSTS to always connect using https
.
As described in Middleware, services and middleware can be composed though HSTS is something you may want enabled across all your routes.
Configuration
By default HSTS
is configured to indicate that all requests during 1 year
should be done over https
and it will contain the includeSubDomains
directive by default.
If you want to preload
or change other default values you can pass a custom header, e.g.
import org.http4s.headers._
// import org.http4s.headers._
import scala.concurrent.duration._
// import scala.concurrent.duration._
val hstsHeader = `Strict-Transport-Security`.unsafeFromDuration(30.days, includeSubDomains = true, preload = true)
// hstsHeader: org.http4s.headers.Strict-Transport-Security = Strict-Transport-Security: max-age=2592000; includeSubDomains; preload
val hstsService = HSTS(service, hstsHeader)
// hstsService: org.http4s.HttpService = Kleisli(org.http4s.server.middleware.HSTS$$$Lambda$30595/1900062101@3a2e72df)
// Do not call 'unsafeRun' in your code
val response = hstsService.orNotFound(request).unsafeRun
// response: org.http4s.Response = Response(status=200, headers=Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 2, Strict-Transport-Security: max-age=2592000; includeSubDomains; preload))
response.headers
// res5: org.http4s.Headers = Headers(Content-Type: text/plain; charset=UTF-8, Content-Length: 2, Strict-Transport-Security: max-age=2592000; includeSubDomains; preload)