Plug v1.7.1 Plug.SSL View Source
A plug to force SSL connections and enable HSTS.
If the scheme of a request is https
, it’ll add a strict-transport-security
header to enable HTTP Strict Transport Security by default.
Otherwise, the request will be redirected to a corresponding location
with the https
scheme by setting the location
header of the response.
The status code will be 301 if the method of conn
is GET
or HEAD
,
or 307 in other situations.
Besides being a Plug, this module also provides conveniences for configuring
SSL. See configure/1
.
x-forwarded-proto
If your Plug application is behind a proxy that handles HTTPS, you will
need to tell Plug to parse the proper protocol from the x-forwarded-proto
header. This can be done using the :rewrite_on
option:
plug Plug.SSL, rewrite_on: [:x_forwarded_proto]
The command above will effectively change the value of conn.scheme
by
the one sent in x-forwarded-proto
.
Since rewriting the scheme based on x-forwarded-proto
can open up
security vulnerabilities, only provide the option above if:
- your app is behind a proxy
- your proxy strips
x-forwarded-proto
headers from all incoming requests - your proxy sets the
x-forwarded-proto
and sends it to Plug
Plug Options
:rewrite_on
- rewrites the scheme to https based on the given headers:hsts
- a boolean on enabling HSTS or not, defaults totrue
:expires
- seconds to expires for HSTS, defaults to7884000
(three months):preload
- a boolean to request inclusion on the HSTS preload list (for full set of required flags, see: Chromium HSTS submission site), defaults tofalse
:subdomains
- a boolean on including subdomains or not in HSTS, defaults tofalse
:exclude
- exclude the given hosts from redirecting to thehttps
scheme. Defaults to["localhost"]
:host
- a new host to redirect to if the request’s scheme ishttp
, defaults toconn.host
. It may be set to a binary or a tuple{module, function, args}
that will be invoked on demand:log
- The log level at which this plug should log its request info. Default is:info
. Can befalse
to disable logging.
Port
It is not possible to directly configure the port in Plug.SSL
because
HSTS expects the port to be 443 for SSL. If you are not using HSTS and
wants to redirect to HTTPS on another port, you can sneak it alongside
the host, for example: host: "example.com:443"
.
Link to this section Summary
Functions
Plug pipeline callback
Configures and validates the options given to the :ssl
application
Plug initialization callback
Link to this section Functions
Plug pipeline callback.
Configures and validates the options given to the :ssl
application.
This function is often called internally by adapters, such as Cowboy, to validate and set reasonable defaults for SSL handling. Therefore Plug users are not expected to invoke it directly, rather you pass the relevant SSL options to your adapter which then invokes this.
For instance, here is how you would pass the SSL options to the Cowboy adapter:
Plug.Cowboy.https MyPlug, [],
port: 443,
password: "SECRET",
otp_app: :my_app,
cipher_suite: :strong,
keyfile: "priv/ssl/key.pem",
certfile: "priv/ssl/cert.pem",
dhfile: "priv/ssl/dhparam.pem"
or using the new child spec API:
{Plug.Cowboy, scheme: :https, plug: MyPlug, options: [
port: 443,
password: "SECRET",
otp_app: :my_app,
cipher_suite: :strong,
keyfile: "priv/ssl/key.pem",
certfile: "priv/ssl/cert.pem",
dhfile: "priv/ssl/dhparam.pem"
]}
Options
This function accepts and validates all options defined in the ssl
erlang module. With the
following additions:
The
:cipher_suite
option provides:strong
and:compatible
options for setting up better cipher and version defaults according to the OWASP recommendations. See the “Cipher Suites” section belowThe certificate files, like keyfile, certfile, cacertfile, dhfile can be given as a relative path. For such, the
:otp_app
option must also be given and certificates will be looked from the priv directory of the given applicationIn order to provide better security, this function also enables
:reuse_sessions
and:secure_renegotiate
by default, to instruct clients to reuse sessions and enforce secure renegotiation according to RFC 5746 respectively
Cipher Suites
To simplify configuration of TLS defaults Plug provides two preconfifured
options: cipher_suite: :strong
and cipher_suite: :compatible
. The Ciphers
chosen and related configuration come from the OWASP recommendations found here:
https://www.owasp.org/index.php/TLS_Cipher_String_Cheat_Sheet
We’ve made two modifications to the suggested config from the OWASP recommendations. First we include ECDSA certificates which are excluded from their configuration. Second we have changed the order of the ciphers to deprioritize DHE because of performance implications noted within the OWASP post itself. As the article notes “…the TLS handshake with DHE hinders the CPU about 2.4 times more than ECDHE”.
The Strong cipher suite only supports tlsv1.2. Ciphers were based on the OWASP Group A+ and includes support for RSA or ECDSA certificates. The intention of this configuration is to provide as secure as possible defaults knowing that it will not be fully compatible with older browsers and operating systems.
The Compatible cipher suite supports tlsv1, tlsv1.1 and tlsv1.2. Ciphers were based on the OWASP Group B and includes support for RSA or ECDSA certificates. The intention of this configuration is to provide as secure as possible defaults that still maintain support for older browsers and Android versions 4.3 and earlier
For both suites we’ve specified ceritifcate curves secp256r1, ecp384r1 and secp521r1. Since OWASP doesn’t perscribe curves we’ve based the selection on the following Mozilla recommendations: https://wiki.mozilla.org/Security/Server_Side_TLS#Cipher_names_correspondence_table
In addition to selecting a group of ciphers, selecting a cipher suite will also disable client renegotiation and force the client to honor the server specified cipher order.
Any of those choices can be disabled on a per choice basis by specifying the equivalent SSL option alongside the cipher suite.
The cipher suites were last updated on 2018-JUN-14.
Manual Cipher Configuration
Should you choose to configure your own ciphers you cannot use the :cipher_suite
option
as setting a cipher suite overrides your cipher selections.
Instead, you can see the valid options for ciphers in the Erlang SSL documentation: http://erlang.org/doc/man/ssl.html
Please note that specifying a cipher as a binary string is not valid and would silently fail in the past. This was problematic because the result would be for Erlang to use the default list of ciphers. To prevent this Plug will now throw an error to ensure you’re aware of this.
Diffie Hellman parameters
It is recommended to generate a custom set of Diffie Hellman parameters, to be used for the DHE key exchange. Use the following OpenSSL CLI command to create a ‘dhparam.pem’ file:
openssl dhparam -out dhparam.pem 4096
On a slow machine (e.g. a cheap VPS) this may take several hours. You may want to run the command on a strong machine and copy the file over: the file does not need to be kept secret.
Add the resulting file to your application’s priv
directory and pass the
path using the :dhfile
key. It is best practice to rotate the file
periodically.
If no custom parameters are specified, Erlang’s ssl
uses its built-in
defaults. Since OTP 19 this has been the 2048-bit ‘group 14’ from RFC 3526.
Plug initialization callback.