Home network security – Part 2: HTTPS and TLS hardening

Home network security – Part 2: HTTPS and TLS hardening

In part 1, we showed you the basic configuration of our Turris Omnia. In this article, we configure the Omnia to use HTTPS-only and harden its TLS configuration. Using HTTPS-only is a good practice even in your home network.

Contents

  1. The defaults
  2. Requirements
  3. Step by step from HTTP to hardened HTTPS
  4. Summary
  5. Sources
  6. Changelog

Always stay in the loop!
Subscribe to our RSS/Atom feeds.

The defaults

By default, our Turris Omnia is reachable via port 80 (HTTP) and 22 (SSH). HTTP is an unencrypted network protocol. This means that other devices in our local network could monitor and read the network traffic between a computer and the Omnia. Furthermore, we can’t be sure that we are really connected with our Omnia when connecting to 192.168.1.1. There is no cryptographic proof.

The solution: Get a certificate, enable HTTPS (port 443) and disable HTTP. Turris OS already shows a warning message that you should enable HTTPS. You can enable this configuration which uses a Turris certificate and not so strict TLS cipher suites. Use this configuration provided by CZ.NIC if you are not a tech-savvy person. For more tech-savvy people, we provide the following guide.

We want to use our own certificate and only strong/modern cipher suites. If you don’t own a Turris Omnia, you can still try to find according guides for your home router. The idea is to encrypt and authenticate all HTTP traffic between local devices and your router’s web server.

Requirements

This time, we need:

  • our Turris Omnia which is connected with our computer and the internet
  • an SSH client on our computer
  • tools like nmap, sslyze or sslscan to verify our setup

Step by step from HTTP to hardened HTTPS

Our plan is really straightforward: Our Omnia runs Lighttpd, an open-source web server optimized for speed-critical environments. So we have to generate a private key, a public certificate, change the configuration of Lighttpd, and restart our router.

Warning
Be aware: It is possible that you misconfigure Lighttpd. Then your web browser won't be able to connect to your Omnia's web server via HTTP/HTTPS. However, you can always fall back to SSH which remains unaffected by the following guide and reset your Lighttpd configuration. So if you encounter any critical errors, simply use SSH to revert changes.

Step 1: Connect via SSH

The first step is to establish an SSH connection between your computer and your Omnia. This requires that you installed an SSH client on your device (if you use Linux, it is very likely that you have it installed). Windows users can use KiTTY. The password is the “advanced password” which you can configure separately in Turris OS.

The simple command here is ssh root@[turris-router-ip]. It is most likely ssh root@192.168.1.1.

Usability tip: Instead of using a password for SSH, you can use keys. Look at step 3 of part 1 of our web server security series. The steps are identical for your Omnia or other routers that run OpenSSH.

Follow us on Mastodon:
@infosechandbook

Step 2: Generate your private key and certificate

The second step is to create a new folder for certificates and keys: mkdir -p /etc/lighttpd/certs. After that, go to the new folder: cd /etc/lighttpd/certs.

Now, we generate two things:

  1. A private key, using the EC parameter “secp384r1”.
  2. An ECDSA certificate.
Info
Nowadays, ECDSA certificates are widely recommended. If there is no specific reason for you to use RSA certificates, stay with ECDSA.

To create the private key, enter openssl ecparam -name secp384r1 -genkey -noout -out eckey.pem.

The command in detail:

  • openssl ecparam is OpenSSL’s EC parameter manipulation and generation tool.
  • -name secp384r1 uses the EC parameter “secp384r1”.
  • -genkey create an EC private key using the specified parameters.
  • -noout inhibits the output of the encoded version of the parameters.
  • -out eckey.pem writes the new key to “eckey.pem”.

Afterwards, we create a public certificate using the key we just created. Enter openssl req -key eckey.pem -x509 -out ecdsa-cert.pem -subj '/CN=192.168.1.1' -days 365.

The command in detail:

  • openssl req is OpenSSL’s PKCS#10 certificate request and certificate generating utility.
  • -key eckey.pem reads the private key from “eckey.pem”.
  • -x509 outputs a self-signed certificate instead of a certificate request.
  • -out ecdsa-cert.pem writes the public certificate to “ecdsa-cert.pem”.
  • -subj '/CN=192.168.1.1' sets the Common Name of the certificate to “192.168.1.1”.
  • -days 365 means that the self-signed certificate will be valid for the next 365 days (1 year).

Now, there are two different ways to proceed. Enter lighttpd -v to see the version of Lighttpd on your router.

  • If your Omnia still runs Lighttpd 1.4.50, you do not have the possibility to load the private key from its own file. This option is available in Lighttpd 1.4.53 or newer. Due to this, you must append your private key to your certificate file. Enter cat eckey.pem >> ecdsa-cert.pem. Then, delete the private key (since it is appended now) by entering rm eckey.pem.
  • If your Omnia runs Lighttpd 1.4.53 or newer, leave your private key in its separate file. You don’t have to enter an additional command for this.

Finally, we set the permission of our pem file(s) to read-only for the root user: chmod 400 *.pem. You can use the ls -l command to see if all pem files are set to -r-------- 1 root root.

Step 3: Harden your TLS configuration

We generated our ECDSA certificate. Now we configure TLS parameters. Simply using the defaults here results in a warning when we test our connection:

Warning that DH and EC parameters are too weak. In this example, an RSA certificate is used.
Warning that DH and EC parameters are too weak. In this example, an RSA certificate is used. (🔍 Zoom in)

The screenshot of an nmap scan shows that weak DH parameters and a weak elliptic curve are in use. There are also several cipher suites without ECDHE. Frankly speaking, it is unlikely that an attacker easily bypasses this protection. In spite of that, we can change the defaults to modern configuration.

In case of any errors, you may want to revert your changes. So back up the TLS configuration of Lighttpd before changing anything: cp /etc/lighttpd/conf.d/ssl-enable.conf /etc/lighttpd/conf.d/ssl-enable.conf.backup.

Open the TLS configuration of Lighttpd using the vi editor: vi /etc/lighttpd/conf.d/ssl-enable.conf. We are using Vim here. If you never used it before, read some beginner’s guides or use your favorite command line editor.

After opening “ssl-enable.conf”, we change the configuration to:

 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
# IPv4 configuration
$SERVER["socket"] == ":443" {
        ssl.engine = "enable"
        # our self-signed certificate
        ssl.pemfile = "/etc/lighttpd/certs/ecdsa-cert.pem"
        # Lighttpd 1.4.53 or newer: Load the private key from its own file
        ssl.privkey = "/etc/lighttpd/certs/eckey.pem"
        # disable honoring the order of ciphers set in ssl.cipher-list
        ssl.honor-cipher-order = "disable"
        # disable mitigation of client triggered re-negotiation
        ssl.disable-client-renegotiation = "enable"
        # list of enabled cipher suites
        ssl.cipher-list = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305"
        # disable TLS compression
        ssl.use-compression = "disable"
        # add security-relevant HTTP response headers
        setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=63072000; includeSubDomains; preload", "X-Frame-Options" => "DENY", "X-Content-Type-Options" => "nosniff" )
        # disable SSLv2/SSLv3
        ssl.use-sslv2 = "disable"
        ssl.use-sslv3 = "disable"
        # If you use OpenSSL 1.1.1 or higher, use "X25519:prime256v1:secp384r1"
        ssl.ec-curve = "prime256v1:secp384r1"
}

# IPv6 configuration (you only need this if you use IPv6 in your home network)
$SERVER["socket"] == "[::]:443" {
        ssl.engine = "enable"
        # our self-signed certificate
        ssl.pemfile = "/etc/lighttpd/certs/ecdsa-cert.pem"
        # Lighttpd 1.4.53 or newer: Load the private key from its own file
        ssl.privkey = "/etc/lighttpd/certs/eckey.pem"
        # disable honoring the order of ciphers set in ssl.cipher-list
        ssl.honor-cipher-order = "disable"
        # disable mitigation of client triggered re-negotiation
        ssl.disable-client-renegotiation = "enable"
        # list of enabled cipher suites
        ssl.cipher-list = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305"
        # disable TLS compression
        ssl.use-compression = "disable"
        # add security-relevant HTTP response headers
        setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=63072000; includeSubDomains; preload", "X-Frame-Options" => "DENY", "X-Content-Type-Options" => "nosniff" )
        # disable SSLv2/SSLv3
        ssl.use-sslv2 = "disable"
        ssl.use-sslv3 = "disable"
        # If you use OpenSSL 1.1.1 or higher, use "X25519:prime256v1:secp384r1"
        ssl.ec-curve = "prime256v1:secp384r1"
}

# Redirect HTTP to HTTPS
$HTTP["scheme"] == "http" {
        $HTTP["host"] =~ ".*" {
                url.redirect = (".*" => "https://%0$0")
        }
        setenv.add-environment = ( "HTTPS" => "on" )
}

Please note that CHACHA20-POLY1305-based cipher suites require OpenSSL 1.1.0 or higher. Enter openssl version to check your version. In our case, the Omnia runs “OpenSSL 1.0.2s 28 May 2019”, so we can’t make use of ChaCha20-Poly1305 at the moment.

In case of any critical errors, use your backup to revert your changes: cp /etc/lighttpd/conf.d/ssl-enable.conf.backup /etc/lighttpd/conf.d/ssl-enable.conf.

Step 4: Restart and test your connection

After saving, we restart lighttpd: /etc/init.d/lighttpd restart. Try to connect to your Omnia using your web browser. Your web browser should be redirected to HTTPS.

Note
Errors like "NET::ERR_CERT_AUTHORITY_INVALID" or "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT" are normal since we are using a self-signed certificate here. Self-signed certificates are always untrusted by our web browsers. This is normal behavior.

You can validate your TLS configuration using nmap, sslyze and/or sslscan:

  • nmap --script +ssl-enum-ciphers -n -p 443 [turris-omnia-ip]
  • sslyze --regular [turris-omnia-ip]
  • sslscan [turris-omnia-ip]

The following screenshot shows the final configuration using modern cipher suites and TLS 1.2 only:

This is the final configuration using an ECDSA certificate, modern cipher suites and TLS 1.2 only.
This is the final configuration using an ECDSA certificate, modern cipher suites and TLS 1.2 only. (🔍 Zoom in)

This article is part of the "Home network security" series.
Read other articles of this series.

Summary

The above-mentioned configuration enables HTTPS-only and enforces strong TLS cipher suites. One weak point remains: We are using our own, untrusted ECDSA certificate. However, this is sufficient for our purposes since the certificate is only used for internal purposes.

To harden your SSH configuration, you can check our Web server security series part 1.

In part 3a, you can read about using a Turris Omnia as network-attached storage which is a big plus for privacy.

Sources

Changelog

  • Sep 18, 2019: Add information about keeping the private key in its separate file (requires Lighttpd 1.4.53 or newer).
  • Jul 28, 2019: Changed from RSA certificate to ECDSA certificate.
  • Jul 13, 2019: Changed TLS configuration according to current good practices.
  • Dec 8, 2018: Updated code for better understanding, added information about filenames in use, added modern TLS configuration.

See also