Web served
- Web served, part 3: Bolting on PHP with PHP-FPM
- How to set up a safe and secure Web server
If you've followed the steps we laid out in our initial feature, you've got a safe Nginx server all set up and working. It's serving your static pages without any issue. We don't yet have a database, PHP, or anything running on it, but we are ready to take the next step: equipping your Web server with SSL/TLS so that you have the option of serving files via HTTPS.
Using HTTPS doesn't just mean that your traffic is encrypted—encryption is only half of the story and it's useless without authentication. What good is it to encrypt something between two parties if you can't be sure of the identity of the person to whom you're talking? Consequently, being able to serve HTTPS traffic means you must posses a cryptographic certificate attesting to your identity. Acquiring such a certificate requires you prove your identity to one of many Certificate Authorities, or CAs.
This has been made to sound a lot scarier than it really is, because there is money to be made in being a gatekeeper of authentication. Most of the well-known CAs charge tremendous amounts of money for even the simplest identity validation. If you're a business engaging in e-commerce, it might make sense to pay thousands of dollars for an extended validation certificate, but if you're a human being serving Web pages on a home-built server, that kind of expense is ludicrous—and, fortunately, unnecessary.
A very, very brief primer on SSL/TLS
SSL stands for Secure Sockets Layer, though in actuality SSL is rarely used these days. Instead, it's been phased out by the more secure Transport Layer Security. However, the "SSL" acronym is still very much in use because of convention, so I'll be using "SSL/TLS" throughout this article.
SSL/TLS is a combination of technologies, but it's based around PKI and the concept of public and private cryptographic keys. A Web server is issued a public and private cryptographic key pair, along with a cryptographic certificate based on the key pair. When a client wants to initiate an HTTPS session, it asks for the server's certificate. This is checked to ensure that it was issued by a trusted authority, that it covers the URL being requested, and that it hasn't expired or been revoked (this stage is where most browser warnings are generated, because this is where the Web browser decides whether or not it's going to accept the certificate as valid).
The client then chooses a cryptographic item called a pre-master secret, encrypts it with the server's public key, and transmits it to the server. Because of the nature of public key cryptography, something encrypted with a public key can only be decrypted with the corresponding private key. The Web server's ability to decrypt the pre-master secret verifies that it's in possession of the correct private key, and is therefore the entity described in the certificate.
Asymmetric cryptography is slow, though, and the server and client don't continue to use it much longer. Rather, they use an ingenious series of steps to independently but securely transform the pre-master secret into a master secret, which is then used to compute a session key. The session key is a symmetric key, and is used to encrypt and decrypt both sides of the conversation.
But do you need a real certificate?
You don't need a CA-generated certificate in order to serve HTTPS from your Web server. However, having a "real" certificate instead of one you've created yourself means that visitors to your site won't be warned by their browser that your website is potentially malicious.
Using self-signed, self-generated certificates for testing or internal websites is perfectly fine, but using self-signed, self-generated certificates on the public Internet isn't just tacky—it undermines one of the two primary reasons for using HTTPS in the first place. A certificate signed by a recognized CA means there's a reasonable expectation you are who you say you are. Even more importantly, the more self-signed certificates there are, the more browser warnings folks will encounter and dismiss without reading, rendering those warnings increasingly invisible in the rare cases where they're actually valid.
So, yes, you need a "real" certificate.
Types of certificates
Different CAs offer different types of certificates, and typically charge more for the higher classes. However, in almost every case, the cryptographic strength of the certificates is the same across the board—it's only the amount of work that goes into validating the applicant that varies.
When poking around at various CA sites, you might see reference to "Class 1" or "Class 2" or "Class 3" certificates, or "wildcard" certificates, or "extended validation" certificates. However, examine the cipher strength: for most vendors, a "class 1" certificate isn't any more secure than a "class 2" certificate. However, the "class 2" certificate likely comes with additional identity validation, so it's more "trustworthy." The different classes vary wildly by SSL vendor.
One thing that is an established standard, though, is an "extended validation" certificate (or an "EV certificate"). An EV cert gets special treatment in your browser's address bar—in addition to the SSL/TLS "lock" icon, EV certificates get displayed in green.
EV certs are used almost exclusively by CAs for their own websites, and by online stores for URLs directly related to purchasing. They're usually quite expensive to purchase because the "extended validation" is just that—the issuing CA requires lots of documentation from the requester and spends no small amount of time ensuring that the documentation is authentic and that the requester really is the person or company they say they are.
You, however, don't need an EV certificate. You don't really even need any of the fancy add-ons offered by most CAs to wring more money out of applicants. You don't need a "wildcard" certificate (a special type of SSL/TLS certificate that can be used for multiple servers in a domain). In fact, for your personal site you don't need anything other than a straight-up basic SSL/TLS certificate.
And why should you have to pay anything for that?
Getting an SSL certificate for free
Most CAs charge an arm and a leg for certificates, but Israel-based StartCom and their StartSSL service offers basic SSL/TLS certificates for no cost. StartSSL was the first company to offer no-cost certificates, and though some other CAs are now following suite, I've been using StartSSL-issued certs on all the domains I control for going on three years now. I have found them consistently responsive and friendly to every customer service inquiry.
A few years back, Ars published a guide on getting free SSL/TLS certificates with StartSSL. Everything in that guide is still valid. The company does offer more complex and capable certificates for cost, but their free "class 1" offering is absolutely perfect for the type of home-built Web server we're dealing with.
One prerequisite
In order to get an SSL/TLS certificate for a Web server, though, your Web server needs a name. This is because the Web server's name is one of the things that gets validated and is part of the server's identity. If you haven't already registered a .com or a .org domain (or a domain under any of the tons and tons of TLDs available these days), you'll need to do that first.
The fastest way to do that is to sign up with the free version of Google Apps. You can register your chosen domain as part of this process for $8, and you'll get a Gmail-style Web interface where you can send and receive e-mail for up to ten users without paying a dime. This will be very important in just a moment.
Validation
The Ars guide we referenced above describes the process through which you can acquire your free certificates. The reason why registering with Google Apps is important is that you must validate your ownership of your domain. To do that, StartSSL sends an e-mail to either webmaster@yourdomain, postmaster@yourdomain, or hostmaster@yourdomain. You must be able to receive and reply to this e-mail in order to establish that you own your domain.
Once this has been done, you can run the Certificate Wizard on the StartSSL page, continue to follow the steps in the linked article, and generate your certificate. You'll end up with three files:
- A private key file, encrypted
- The SSL/TLS certificate, which contains the public key
- An intermediate certificate, which is necessary for some browsers to correctly understand that StartCom is a CA
We need to do a bit of work to transform those three files into something that's usable by our Nginx Web server—specifically, we need to decrypt and secure our private key, and we need to combine the server and intermediate certificates together into a chain certificate.
StartSSL has a convenient set of instructions for doing these tasks, and we're going to use some of them. Download your private key and your certificate and copy them to your account's home directory on your Web server. This can be done using the scp
command, like so:
scp ssl.key yourname@webserver:~ scp ssl.crt yourname@webserver:~
Assuming the key file is named ssl.key
and the certificate is named ssl.crt
. Substitute in your username for yourname
and your Web server's name for webserver
. Next, let's make a place under the Nginx directory for the files to live and move the key and certificate there:
sudo mkdir /etc/nginx/ssl sudo mv ssl.key /etc/nginx/ssl/ sudo mv ssl.crt /etc/nginx/ssl/
Once the key and certificate have been placed, you'll need to decrypt the key. Do this with the following command:
sudo openssl rsa -in ssl.key -out /etc/nginx/ssl/ssl.key
You will be prompted first for your account's password for the sudo
elevation, and then for the key's password, which you will have entered when creating the key. The openssl
tool will then place a decrypted copy of your private key in the /etc/nginx/ssl
directory (which is why we are using sudo
—otherwise, you can't write files into that directory).
It's very important that this key be kept absolutely secret. It is the basis of your Web server's encryption identity, and whoever possess it can cryptographically impersonate your Web server. We need to change the file's ownership and permission so that only the root user can read it:
sudo chown root:root /etc/nginx/ssl/ssl.key sudo chmod 400 /etc/nginx/ssl/ssl.key
The first command changes ownership of the file to the root
user, and the second sets the permissions on the file so that only the owner can read from it. This way, even if your site is compromised, the SSL key will be protected from access unless the attacker gains root.
Next, we need to get the intermediate and root certificates from StartSSL and combine them with the server certificate into one big chain. In addition to making it easy for Web browsers to understand the certificate, this also is the easiest way to get Nginx to serve out the certificate.
cd /etc/nginx/ssl sudo wget http://www.startssl.com/certs/ca.pem sudo wget http://www.startssl.com/certs/sub.class1.server.ca.pem
These three commands get you to the directory you need to be in, then retrieve the root and intermediate certificates from StartSSL. With all three files now present in the ssl
directory we've created, use the following command to concatenate them all together into a single file:
sudo cat ssl.crt sub.class1.server.ca.pem ca.pem > /etc/nginx/ssl/ssl-unified.crt
The certificate files are all just text, and we're simply taking advantage of the power of the Unix-like shell and smushing them back-to-back in a single file.
Plugging it all into Nginx
Now comes the magic. We've got our decrypted key and our certificate, and we need to tell Nginx how to use them. There are two files to edit in order to make this happen—the main nginx.conf
file and your virtual host file. If you have several websites and several virtual host files, you'll need to edit each one. For this example we're going to assume you just have a single virtual host.
Open nginx.conf
for editing and add the following at the bottom:
ssl_session_cache shared:SSL:10m;
This setting will be applied globally and sets up a shared 10MB session cache—that is, a place where the Web server stores information about active SSL connections—across all of your virtual hosts.
Then, open up your virtual host file. If you've followed the instructions in our initial feature, you've only got the one virtual host file. It currently contains a non-SSL host listening on port 80; we're going to add a new host to the file, in effect creating a second website, listening on port 443. It will have the same locations listed, but its configuration will be different in order to enable HTTPS. Add the following section below the existing server
stanza:
server { listen 443 ssl; root /usr/share/nginx/html; index index.html index.htm; server_name your-server-name; ssl on; ssl_certificate /etc/nginx/ssl/ssl-unified.crt; ssl_certificate_key /etc/nginx/ssl/ssl.key; ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4: HIGH:!MD5:!aNULL:!EDH:!AESGCM; ssl_prefer_server_ciphers on; ssl_ecdh_curve secp521r1; }
One key thing to note here is that you need to specify the domain name for which the SSL/TLS certificate has been issued for the server_name
directive. Otherwise, you'll get a certificate warning when you try to access the Web server via HTTPS because the name the server identifies itself with won't match the hostname on the certificate. You might need to make an entry in your computer's hosts
file so that your computer knows how to correlate that name with your Web server's LAN IP address.
There are several differences between the original non-HTTPS server
block. First, the listen
directive specifies port 443. When there is no listen
directive in a server
block, Nginx assumes port 80. Here, though, we want Nginx to listen on the standard HTTPS port and that's TCP 443.
Next, the ssl
directives:
ssl_on
: Indicates that SSL/TLS will be active for this serverssl_certificate
&ssl_certificate_key
: Tells Nginx where to find the SSL/TLS certificate and key.ssl_protocols
: Tells Nginx which versions of SSL and TLS it's able to use. Ubuntu 12.04 comes with version 1.0.1 of the OpenSSL libraries, and so it supports the latest released version of TLS, 1.2.ssl_ciphers
: Tells Nginx which ciphers it's allowed to use when encrypting traffic, in order of preference. The list of ciphers here should work in all modern browsers and are proof against the BEAST attack.ssl_prefer_server_ciphers
: Tells Nginx to not listen to the client's list of supported ciphers and to instead demand the client use the server's preferences. This prevents old or misconfigured browsers from negotiating a connection with an older, less-secure cipher.ssl_ecdh_curve
: Specifies the type of curve used for the elliptic curve algorithm, if that type of cipher is used. The curve specified here,secp521r1
, provides good encryption.
Once these lines have been added, reload Nginx to make the configuration active:
sudo /etc/init.d/nginx reload
The name game
If you've followed the previous article, your server is already reachable on the Internet. You'll want to expose TCP port 443 to the Internet by the same method you exposed TCP port 80 in order for your new HTTPS connectivity to be usable. Alternately, if your ISP blocks incoming requests on TCP 443, you'll need to specify a different port (like 4433 or 4443).
Of more importance, though, is ensuring that your domain name points to your external IP address, because only browser requests to your domain name will result in error-free HTTPS communication. If you happen to have a static IP address for your home connection, this is easy. If not, there are services like No-IP and DynDNS that will keep your domain name pointed at your home connection's dynamic IP address.
Checking if it works
If it all worked, accessing your site by name with HTTPS should yield something like this:
That's my personal site. I'm using a class 2 wildcard certificate on it, but the results with a class 1 certificate should be much the same.
You can also get some independent verification of your site's SSL/TLS functionality by heading over to SSL Labs and testing your setup. The free site evaluation there will tell you how it perceives your SSL/TLS configuration to be set, and it will also let you know if you've chosen weak or vulnerable ciphers.
Why the bother?
It's a bit more complicated to set up SSL/TLS than to simply serve unencrypted traffic, but encryption is important. It helps to ensure the content of your browsing session is private, which is a good thing. If you're sitting in Starbucks, for example, everything you're sending or receiving over that public Wi-Fi connection is viewable by anyone else on the same WLAN with the right tools. An encrypted Web server at least helps guarantee the pages you're browsing on your server are unreadable to anyone except you. Beyond that, it's good practice. Learning how to set up an encrypted website gives you one more useful thing that you can do.
So, we've got a Web server that can serve encrypted and unencrypted static content. You know what would be really great? The ability to serve some dynamic content! Well, stay tuned: next, we're gonna' learn how to get PHP-FPM up and working.
No comments:
Post a Comment