GitHub Pages + Custom Domains + HTTPS Certificates. Secure Enough?

Tue, 2018-05-01 20:46

GitHub announced that GitHub Pages with custom domains can now use HTTPS with TLS certificates obtained thanks to LetsEncrypt. Before this, if you wanted to serve your site over HTTPS, you had to put a front-end proxy such as CloudFlare.

GitHub pages is a free service and comes with many useful features such as DDoS protection and a CDN from Fastly. I'm grateful for their service of course, but here is a brief review of its HTTPS implementation and usage. For the Certificate and TLS implementation topics in this article, I used the output from openssl s_client -showcerts -servername github-test.ayeshious.com -connect github-test.ayeshious.com:443 </dev/ null, but you can also see the certificate information from the crt.sh entry.

Enabling HTTPS

This is automatic. When you set a custom domain, GitHub automatically obtains a TLS certificate for that domain and your domain will be available over HTTPS in a few seconds.

You can optionally force HTTPS.

What I love about this implementation is that you don't have to do anything. If you already have a custom domain setup, your site is automatically HTTPS-ready!

Certificate

The certificate is a standard LetsEncrypt-issued certificate with ISRG/IdenTrust root, Let's Encrypt intermediate certificate. There are no other domains in the X.509 Subject Alternative Name field. This is great because if you were using CloudFlare, CloudFlare often obtains certificates for a bunch of domains owned by different users into one TLS certificate.

Certificate lifetime is the standard 90 days period.

RSA certificates only. No ECC certificate support
It doesn't look GitHub Pages use ECC certificates. ECC certificates have shorter keys, and in ECDHE_RSA vs ECDHE_ECDSA comparison (meaning the RSA certificate authentication vs ECC certificate authentication), the latter is 2.7 times faster.

OCSP must-staple
OCSP must-staple is a TLS extension that the certificate itself enforces the browser to expect a valid OCSP response during the TLS handshake. One can easily shoot themselves in the foot with this because if your web server could not properly cache and staple an OCSP response, browser will refuse to connect. In GitHub Pages HTTPS implementations, certificates do not have this flag set.

Certificate Transparency SCT in certificates
Lets Encrypt recently started to log all certificates they issue to public logs, and include their timestamps in the certificates. This is not something the certificate requester can control, but I thought to point it out anyway because Chrome recently started to mark HTTPS connections that do not provide this information (along the certificates or other means) as insecure.

TLS Handshake

TLS 1.2 only
TLS 1.0 was introduced in 1999 and TLS 1.1 in 2006. While you can use TLS 1.0 securely, it lacks many ciphersuites that we use in modern PKI. I'm glad they got rid of them.

Unfortunately, TLS 1.3 is not supported yet, but I'm pretty sure it will be soon, knowing how good GitHub is at implementing modern HTTPS practices.

Cipher Strength
Prefers AES in GCM mode with 128-bit keys first. This is pretty much the industry standard as of today.

Perfect Forward-Secrecy
Yes, Si, Oui. Only ECDHE (last E stands for Ephemeral) key exchanges are used, providing perfect forward secrecy.

OCSP response staples
During the TLS handshake, server sent the OCSP information, saving my browser from making a separate request to the Certificate Authority (Lets Encrypt) to check the certificate status. Browsers nowadays give up and trust the certificate is the OCSP responder is down or very slow. When this information is stapled, all browsers get to see the OCSP response and can be more assertive of the certificates validity.

HTTP security headers

Unfortunately, with GitHub Pages, you cannot set custom HTTP headers. This makes it not possible to set security headers such as Content Security Policy, Referrer Policy. HSTS, or HTTP Strict-Transport-Security header instructs browser to remember to always use HTTPS on that site. Even with the Enforce HTTPS option enabled in GitHub Pages settings, this header is not set by the browser, so your users browsers will often make requests to plain HTTP version of the site before they are redirected to their HTTPS counterpart.

You cannot set custom HTTP headers, but you can use HTML <meta http-equiv="HEADER_NAME" content="HEADER_VALUE"> pattern set within page <head> tag. RFC 6797 dictates that the HSTS header must be set as a regular HTTP header, and browsers should not consider <meta http-equiv /> valid, so it is impossible to enforce HSTS with GitHub Pages yet.