heroku / Snit
Programming Languages
snit
Snit is Heroku's library for providing a basic, safe configuration for SNI terminating servers.
It provides a set of options that make it safe to set up a public-facing Erlang/OTP TLS server to the public. This work includes:
- Setting up a general security policy (based on Mozilla's and AWS) for cipher suites and their ordering
- Prioritizing ECCs to be performant and matching other industry players
- Disabling client-initiated renegotiations, and mandating secure one otherwise
Build
You'll need an Erlang version of 18.0 or newer. You can install one with
kerl
by calling:
$ kerl build git https://github.com/erlang/otp.git OTP-19.1 OTP-19.1
Note that on OSX, you will need the newest cipher suites available.
$ brew update
$ brew upgrade openssl
Note the version you have (for example, 1.0.2a-1
) and tell kerl
to use it:
$ KERL_CONFIGURE_OPTIONS="--with-ssl=/usr/local/Cellar/openssl/1.0.2a-1" build git https://github.com/erlang/otp.git OTP-19.1 OTP-19.1
The project itself relies on rebar3. Install a copy and compile the project:
$ rebar3 compile
Tests
$ rebar3 ct
Browser Tests
The first step will be to add an hostfile entry on any client computer you
will use to test browsers, pointing the snihost.custom
domain to the
computer on which the server is running (the self-signed certificate is
signed using that domain and it must be used to work).
First, make sure you know your server's IP (we aim for IPv4 here):
- If the server is public, you can find it by googling 'what is my ip'
- if it's on your local network, you can use
ifconfig -a inet
and look for the address that is not onlo0
(loopback, localhost) on OSX and Linux, oripconfig /all
on Windows, and look for theIPv4 Address
entry noted with(Preferred)
after it. - If it's on the same computer, use
127.0.0.1
.
Then find the host file, Add an entry in there saying:
127.0.0.1 snihost.custom
(using whatever IP yours is rather than 127.0.0.1
). Everrything is set.
Start the snit
server:
$ rebar3 as demo shell
1> application:ensure_all_started(snit).
snit:start(http, 10, 8080, fun(_) -> [
{certfile, "test/snit_basic_SUITE_data/selfsigned.crt"},
{keyfile, "test/snit_basic_SUITE_data/selfsigned.key"}
] end, snit_http_hello, []).
Then open a browser to https://snihost.custom:8080
. Do note that exceptions
will need to be added on browsers, and Chrome may never be happy with a custom
certificate on localhost if they require a CA chain that it can't resolve.
Self-signed certificates appear to be fine.
A connection can be debugged and inspected using the openssl
debug client:
$ openssl s_client -connect snihost.custom:8080 -tls1 -servername -state 2>&1
Configuration
All configuration values are general to snit, and can be set through your sys.config
file or through application:set_env(snit, VarName, ValName)
for the more dynamic case.
- ALPN: use the variable
alpn_preferred_protocols
with a list of binary strings. Defaults to[<<"http/1.1">>]
- Cipher suites are configured with the
cipher_suites
option. The syntax is specific to be friendly both to people familiar with the OpenSSL notation and the internal Erlang one and more accurately described in src/snit.app.src. Defaults to what should be a safe policy. - ECCs selection and order are configured (in OTP-19.2 and later) through the
eccs
option. It accepts a list of atoms, and by default favors suites in order of 256 bits, 384 bits, and then from largest to smallest bit count. The objective there is to balance the speed of curves with security, where the default of secp256r1 is still generally a very good compromise. See the description for the configuration in src/snit.app.src
Contributing
Contributing to this repository should be done through, generally, updating the configurations to line up with the Erlang/OTP ones that are made available, for the most secure configuration possible while remaining generally compatible with a wide group of users.
Tests should be accompanied by tests, and a strong rationale in the pull request as to why the new configuration ought to be safer than the existing one.
The patches will then be reviewed and double-checked before being merged. We do not necessarily expect to give very rapid responses since every default configuration change may be far-reaching and require careful validation.
On top of a strong rationale, we also expect:
- Tests
- Proper commit description
- Related documentation
Changelog
- 1.0.2: allowing to specify versions rather than enforce them (i.e. disable tlv1), but switch the previous versions to defaults
- 1.0.1: adding OTP-21 support
- 1.0.0: open-source release
- 0.3.2: ECC curve selection
- ?.?.?: whole lot of stuff