Deploying HTTPS (Jan 2014, revised Jun 2015)
What HTTPS does
A plain HTTP connection runs inside a TCP connection1.
An HTTPS connection runs a HTTP connection inside an SSL/TLS connection which runs inside a TCP connection.
In the common case, SSL/TLS allows the web client to know2 that, whatever "example.com" is, they are getting the real "example.com" and not something modified by a man-in-the-middle (MITM). It also prevents3 MITMs from seeing anything more about the connection than who's connecting, how much data they are transferring, and the time they are doing it. None of these protections work unless the server has a certificate whose public key is signed by a widely-trusted certificate authority (CA) and whose private key is visible only to the "example.com" servers.4 It doesn't allow the web server to know anything.5
SSL was created in the 1990s when cryptography was not as thoroughly understood. Some of its cryptographic choices are poor and/or vulnerable. It's not entirely broken yet though. To stay secure-ish, stay up-to-date with the best deployment practices (e.g. Mozilla's guide). SSL and TLS mean the same thing. They are versions of a standard whose revisions are named SSL 2.0, SSL 3.0, TLS 1.0, TLS 1.1, TLS 1.2, etc (in that order). All "SSL X.Y" versions have been cryptographically broken by now. TLS 1.0 and up are still usable as of this writing (5 June 2015). (The standards writers renamed SSL to TLS because the acronym for TLS is slightly more accurate. I'm not sure why they reset its version number to 1.0 at that time.)
A way to get HTTPS for a website you host
Before every step, make sure that the private key (example.com.key) will not be readable by any user but the web server (and potentially its admins and backups, depending on security vs. availability tradeoffs).
Keypair creation
SSL/TLS certificates are in X.509 format.
openssl
is a command-line program for working with (among other things) X.509 keys. To read documentation on openssl
flags, run man openssl
, man req
, man dhparam
, etc. (Also, here's another SSL/TLS tutorial.)
Even the cheapest CA-signed certificates certify both www.example.com and example.com. To create a key-pair to be signed by a CA:
openssl req -new -newkey rsa:2048 -sha256 -days 1095 -nodes \
-subj '/CN=example.com/O=me/OU=me/C=US/ST=New York/L=New York' \
-keyout example.com.key -out example.com.csr
At least for cheap domain-validation certificates, CN=
must be the domain you wish your key to be for. The other parts of -subj
don't matter and probably won't be used by a cheap CA but are required by some of them even though they don't use it. A fancier certificate might copy some of those into the public certificate you share with the world.
To create a self-signed certificate, add -x509
, change .csr
to .pem
, and use example.com.pem
in place of an example_com.crt
a CA might provide.
I chose 3 years to expire: long enough that replacing the cert a month before it expires won't be tiresome, and short enough that today's best-practice SSL/TLS certificate sizes and types might still be tolerably secure throughout its valid duration.
The filename extensions don't actually make a difference, but this is approximately what they indicate:
.key
- private key
.csr
- certificate-signing request (it's like a public key with metadata that will be transformed into a different, X.509, public key by a CA)
.pem
- a standard format for an X.509 public key with metadata, or various other things (PEM stands for "Privacy-Enhanced Mail" but is really just header+base64(data)+footer without specifying the enclosed data. All of these files match that format.)
.crt
- the subset of .pem format files that are signed by a CA
Then submit the .csr
file contents to your CA/reseller (see choosing a CA below).
They should give you a signed X.509 version of your public key and their certificate chain. GoGetSSL e-mailed me a .zip of the following signed public certificates:
AddTrustExternalCARoot.crt
- Comodo's root certificate, self-signed, included in most browsers' list of trusted certificates.
COMODORSAAddTrustCA.crt
- intermediate certificate signed by AddTrustExternalCARoot, not to be confused with a root certificate also named COMODORSAAddTrustCA that is included in some browsers and that also signs COMODORSADomainValidationSecureServerCA.
COMODORSADomainValidationSecureServerCA.crt
- intermediate certificate that's authorized to sign certificates, signed by COMODORSAAddTrustCA.
idupree_com.crt
- signed by COMODORSADomainValidationSecureServerCA.
Forward secrecy
To create Diffie-Hellman parameters so that the server can support ciphers with forward secrecy (ephemeral Diffie-Hellman), run this command (which takes a while):
openssl dhparam 2048 -out dhparam.pem
Web server configuration (nginx)
I used nginx. (Other servers vary a bit; e.g., not all use .crt
concatenation). In general, follow Mozilla's guide and check it every year or so to see if best practice has changed. For reference, Nginx HTTP SSL documentation. The HTTP SSL configuration can go inside http{}
or inside server{}
. For the fields underspecified by Mozilla's guide:
The server needs to use the private key.
ssl_certificate_key /path/to/idupree.com.key;
The server needs to serve your site's signed certificate and the intermediate certificate(s) to clients.6 (It can, but needn't, serve the root certificate too.) For nginx, concatenate idupree_com.crt
, COMODORSADomainValidationSecureServerCA.crt
, and COMODORSAAddTrustCA.crt
(in that order) to make, say, idupree_com+COMODORSADomainValidationSecureServerCA+COMODORSAAddTrustCA.crt
and configure
ssl_certificate /path/to/idupree_com+COMODORSADomainValidationSecureServerCA+COMODORSAAddTrustCA.crt;
If you want your server to support OCSP stapling (which is a good practice), that requires another concatenation.
ssl_trusted_certificate /path/to/COMODORSADomainValidationSecureServerCA+COMODORSAAddTrustCA+AddTrustExternalCARoot.crt;
OCSP stapling also requires a DNS resolver IP address. Level 3's 4.2.2.2
and Google's 8.8.8.8
are fine.
resolver 4.2.2.2;
Forward secrecy by ephemeral Diffie-Hellman requires
ssl_dhparam /path/to/dhparam.pem;
Testing
Point SSL Labs' testing site at your site and look through the results for anything you can improve.
openssl s_client
can be a nice debugging tool; e.g. see.
Server Name Identification (SNI) note
This is supported by all modern operating systems so you "shouldn't" have to worry about it.
In order to support Internet Explorer on Windows XP, or Android ≤ 2.3, to have HTTPS without certificate warnings, you have to reserve one IPv4 address per SSL/TLS certificate.
Choosing a certificate authority
These are not endorsements, just options I've found.
Basic domain-validation certificates usually include both example.com
and www.example.com
in the same certificate, but require separate certificates for other subdomains. For the next order-of-magnitude in price, one certificate can contain many domains/subdomains (subjectAltName), and/or a wildcard *.example.com
that certifies foo.example.com
but not bar.foo.example.com
or example.com
unless the certificate lists those separately.
If you're mainly price-focused and only need HTTPS for a few domains, the cheap options I found were Comodo resellers and StartSSL. Resellers are often much cheaper than the CA's price. I'm not sure what economics are behind that.
Some Comodo resellers: Namecheap and GoGetSSL. US$5-10/year/site for the cheapest domain-validation certificates.
StartSSL is free as long as you are noncommercial7, and are willing to probably pay US$25 if your key needs to be revoked or re-created before expiry8, and only need a domain-validation certificate, and are willing to go through the same hassle every 365-minus-epsilon days.
You can self-sign if you don't need the certificate to be valid for anyone else, but it's either a nuisance installing your certificate in all your client software manually, or if you don't, it exposes you to MITMs (at least the first time you connect with each application on each device).
You may be able to use Let's Encrypt by the time you read this; if that comes to pass, it's time to update this page to promote that option in a more prominent place.
A TCP connection is composed of IP (v4 or v6) packets, which are encapsulated in link-layer packets on physical media such as Ethernet and WiFi. A more thorough treatment of these layers: https://en.wikipedia.org/wiki/OSI_model↩
assuming the server is correctly configured, neither the server nor the client is compromised, the negotiated TLS cipher isn't broken, and no certificate authority has been tricked/bribed/cracked into issuing a fraudulent certificate for that domain.↩
If a TLS cipher that lacks forward secrecy is used, a later server compromise can reveal all past transferred data to past eavesdroppers who stored the ciphertext. TLS ciphers with forward secrecy contain "DHE" or "ECDHE" ([elliptic-curve] Diffie-Hellman ephemeral) in their names.↩
and inevitably visible to some of the servers' admins too. (Unless the server manages its TLS keys with some sort of hardware assistance such as a TPM or USB security token that's properly configured. If you know more information on this, I'd love to hear more. Apparently some TPMs are not fast enough for a public server: this blogger's TPM "can do about 1.4 connections per second". Another thing that may help depending on your concerns: You may be able to move the private key unauthorized access ability from your admins to only a hosting service's admins.)↩
A man-in-the-middle could be communicating to the user by HTTP and the server by HTTPS to give the server an impression that there's an end user connecting securely. Also, businesses can ask their employees to install SSL MITM certificates, which their employees can be aware of but the server can't. The server can, however, receive some guarantees from client certificates, which I won't discuss here.↩
All browsers that trust Comodo have a copy of their AddTrustExternalCARoot.crt, but not all have COMODORSAAddTrustCA.crt and COMODORSADomainValidationSecureServerCA.crt, and probably none have a copy of idupree_com.crt. Browsers need a copy of every certificate in the chain to verify that the Comodo they trust signed your certificate. Your browser won't necessarily warn you, but SSL Labs' test site will list next to "Chain issues" if the server is serving fewer or more certificates than it needs to.↩
StartSSL's policy (PDF) § 3.1.2.1 "Class 1 certificates are limited to client and server certificates, whereas the later is restricted in its usage for non-commercial purpose only."; a user's experience. This policy is not standard; it is just a money-making decision by StartSSL.↩