summaryrefslogtreecommitdiff
path: root/content/posts/2022/2022-02-20-nginx-tls.md
blob: 0baef4308cc4e2af816dea8350d89af5dda3e74c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
---
date: 2022-02-20
title: Updating NginX TLS settings for 2022
tags:
- TLS
- NginX
---

My blog (and pretty much every other site I host) is using Let's Encrypt
certificates in order to be served over https. Using any certificate at all is
generally an upgrade when it comes to security, but your webserver's
configuration needs to be up to standard as well. Unlike the Let's Encrypt
certificates, keeping the configs up to date requires manual intervention, and
is therefore something I don't do often.

This week I decided I should check up on the state of my SSL configuration in
nginx. I usually check this through [SSL Lab's SSL Server
Test](https://www.ssllabs.com/ssltest/analyze.html). This is basically
[testssl.sh](https://testssl.sh/) in a shiny web frontend, and assigns you a
score. I aim to always have A or higher, but it seemed my old settings were
capped at a B. This was due to the cipher list allowing ciphers which are
nowadays considered insecure.

While I could've just updated the cipher list, I decided to check up on all the
other settings as well. There's a [GitHub
gist](https://gist.github.com/gavinhungry/7a67174c18085f4a23eb) which shows you
what settings to use with nginx to make it secure by modern standards, which
I've used to check if I should update some of my own settings.

My old settings looked as follows. Please don't be too scared of the giant list
in the `ssl_ciphers`.

```nginx
# DHparams
ssl_dhparam /etc/nginx/dhparam.pem;

# SSL settings
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_tickets off;
ssl_session_timeout 1440m;

# Additional headers
add_header Strict-Transport-Security "max-age=63072000" always;
```

With the new settings, I've added `ssl_buffer_size` and `ssl_ecdh_curve`. A
friend on IRC pointed out I should enable `ssl_prefer_server_ciphers`, so this
has been enabled too.

But most notably, the list of `ssl_ciphers` has been dramatically reduced. I
still allow TLSv1.2 in order to allow slightly older clients to connect without
any issues, but the ciphers considered *WEAK* have been disabled explicitly.
This leaves a total of 5 ciphers to use, all of them using ECDHE, so the
`ssl_dhparam` could be dropped as well.

Lastly, I've added a couple headers for security reasons, as recommended by
[securityheaders.com](https://securityheaders.com).

```nginx
# SSL settings
ssl_protocols TLSv1.3 TLSv1.2;

ssl_buffer_size 4K;
ssl_ecdh_curve secp521r1:secp384r1;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:le_nginx_SSL:2m;
ssl_session_tickets off;
ssl_session_timeout 1440m;

ssl_ciphers 'EECDH+AESGCM:EECDH+AES256:!ECDHE-RSA-AES256-SHA384:!ECDHE-RSA-AES256-SHA';

# Additional headers
add_header Content-Security-Policy "default-src 'self'" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
```

{{< admonition title="note" >}}
I would still like the `ssl_ciphers` to be formatted in a more clean way, which
I've tried to do with a variable through `set`, but it appears variables are not
expanded within `ssl_ciphers`. If you have any methods to format the list of
ciphers used in a cleaner way, I'd be very happy to know!
{{< / admonition >}}

This configuration is saved as a small snippet which I `include` in all other
site configurations, so it is updated everywhere at once as well. Now I should
be able to neglect this for another year or two again.