Secure Own-/ Nextcloud setup

update 24.04.2017 –  include Subject Alternative Name field
update 20.12.2017 – discuss Certbot as an alternative

While the Nextcloud Manual suggests enabling SSL, it unfortunately does not go into detail how to get a secure setup. The core problem is that the default SSL settings of Apache are not sane as in they do not enforce strong encryption. Furthermore the used default certificate will not match your server name and produce errors in the browser.

In the following a short guide how to manually set-up a secure Apache 2.4 server for Nextcloud will be presented.

Note: nowadays one can also use Certbot to automatically perform the steps below and validate your certificate so browsers accept it. However due to their certificate transparency policy, your host will be submitted to a public list. This may or may not be what you want.

Generating a secure Certificate

A secure TLS connection starts with the Server authenticating itself to the client with the server certificate. Therefore we will start the setup of our server with generating that certificate.
The purpose of the certificate is to ensure that if you type in “your.website.net” you are indeed talking to your server and not to a man-in-the-middle who intercepted your connection. Therefore the certificate contains the server name and the public key of the server.

As mentioned above the default certificate will not match your server name and therefore you will have to generate a matching one.

Unfortunately following the apache SSL FAQ will results in a certificate using the possibly vulnerable SHA-1 hashing function. A better alternative is SHA-256, but it has to be explicitly requested during certificate creation. The according call to openssl for certificate creation is

openssl req -new -sha256 -x509 -nodes -days 365 -out your.website.net.pem -keyout your.website.net.key

Use man req to display a detailed description of the options used above.

Setting the Subject Alternative Name field

Starting with Chrome 58, the the deprecated Common Name (CN) field is no longer recognized. Instead the Subject Alternative Name (SAN) field is now mandatory.

Unfortunately openssl does not simply ask you for it like it does for CN, but you have to append the following rather clumsy command line option

-config <(cat /etc/ssl/openssl.cnf <(printf "[v3_ca]\nsubjectAltName=DNS:your.website.net"))

the full command is then

openssl req -new -sha256 -x509 -nodes -days 365 -out your.website.net.pem -keyout your.website.net.key -config <(cat /etc/ssl/openssl.cnf <(printf "[v3_ca]\nsubjectAltName=DNS:your.website.net"))

Configuring Apache

The resulting certificate and private key have to be referenced in your website configuration. On Debian/ Ubuntu you have to edit
/etc/apache2/sites-enabled/owncloud.conf

SSLCertificateFile    /path/to/your.website.net.pem
SSLCertificateKeyFile /path/to/your.website.net.key

Note that this results in a so called self-signed certificate. Usually certificates on the web are approved by a Certificate Authority (a digital notary) which confirms your identity. By trusting the CA you can also trust websites that are otherwise unknown to you, but which were approved by the CA.
While this makes sense for public websites, you probably already trust your own server, so there is no need for a CA signed certificate.
Just add your self-signed certificate to the trusted list of your browser on first visit.
If you fear a man-in-the-middle attack during the initial connection, you can also manually copy the generated pem file on a USB-drive and import it in the browser from there.

Using secure ciphers

Using the secure certificate we only know that we are indeed talking to the server we want to talk to. Next we actually want to start sending encrypted messages. In theory we could encrypt data with the public key of the server using asymmetric encryption like RSA. However asymmetric encryption is slow and therefore not suitable for large amounts of data. Furthermore our communication could be decrypted if somebody would record it and at some point in the future get access to the private key of the server. Therefore we want to use a one-time symmetric key. This way we achieve forward secrecy.The symmetric encryption should be also secure in a sense that even when large amounts of data is collected, it is must not be possible to reconstruct the key and decode the data.
Last but not least the chosen cipher should be supported by our clients. Surprisingly it is the Owncloud desktop client which does not support modern ciphers, while current browsers and even the android app does.

Instead of discussing all available ciphers in regard of the above requirements, I would rather refer to the excellent TLS server configuration guide by Mozilla.
Yet we can still improve the suggested configuration. Mozilla has to consider compability with old web-browsers which we do not have to. So without further ado this is the recommend cipher configuration

SSLProtocol all -SSLv2 -SSLv3
SSLCompression off
SSLHonorCipherOrder On
SSLCipherSuite EECDH+AESGCM:EECDH+AES

The rationale behind this suggestion is

  • Allow TLS 1.0 for compability with mobile apps
  • Disable SSL compression to mitigate the CRIME attack
  • always use Diffie Hellman(DH) key exchange(Kx) for forward secrecy
  • use Elliptic Curve Diffie Hellman (ECDH) variant for performance
  • always use AES for symmetric encryption
  • prefer AES GCM mode for security and performance

Notes

The only reason for allowing TLSv1 is compability with the mobile apps because openssl on android up to 4.4 does not yet support TLS1.1+. This circumstance is not really critical as BEAST is not applicable in the sync apps and browsers will connect to the server with TLS1.1+ or work around the vulnerability.
However if you are on android 5.0+ you can add -TLSv1 to SSLProtocol to enforce a TLS1.1+ connection.

Update: The issue with the Owncloud desktop client that forced us to enable non EC DH key exchange was fixed in version 1.7.1.
If you need compatibility with desktop clients older than 1.7.1 append EDH+AES to SSLCipherSuite
However besides being much slower than ECDH, a weak modulus is used for DH Kx up to (including) Apache 2.4.6. While there are no practical attacks exploiting this yet, we can only be completely on the safe side by updating to Apache 2.4.7.

To see which actual ciphers the SSLCipherSuite determines, run

openssl ciphers -V 'EECDH+AESGCM:EECDH+AES -SSLv3'

possible output:

 0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
 0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
 0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
 0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
 0xC0,0x28 - ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
 0xC0,0x24 - ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
 0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
 0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256

 

Enforcing HTTPS

At this point the secure connection to your server is ready, but we still have to ensure that it is the only way data is exchanged with the clients.
While you can only enable apache on port 443, you will always have to remember to type in https:// in the browser. A better way is to automatically redirect from port 80 to port 443 like

<VirtualHost *:80>
        ServerName your.website.net
        Redirect permanent / https://your.website.net/
</VirtualHost>

Note that you do not have to use mod_rewrite here as Owncloud sets the HSTS header, so browsers will automatically prefix all requests with https after the first visit.

But whatever you do, remember this