Protecting a Website with Mutual Authentication

Configuring your web server to demand a client certificate provides another significant layer of armour worth far more than the 30 minutes it’ll take to enable this countermeasure. By using your own signing certificate your web server will only allow connections from clients that can produce a certificate signed by your root. Keep that root key safe and you’ve created a barrier very difficult to circumvent.

Creating the Root Certificate

You can use the following shell script and OpenSSL configuration file to generate your own self signed root certificate:

Copy those into the same directory and as long as you have openssl in your path then all you need to do is execute the shell script and follow the prompts. If you edit the conf file first you can change some of the default values. After the script completes executing you will have a self signed root certificate and key. Make sure you keep the private key in a safe place and encrypted. Here’s how to encrypt it:

# openssl rsa -in root_CA.key -des3 -out
# mv root_CA.key

Creating the Client Certificate

Create a private key:

# openssl genrsa -des3 -out client.key 1024

Since you’re forced to set a password for the private key, run the following commands so the private key is not encrypted with a password otherwise you need to enter the password in every time you authenticate (which could be what you want so feel free to skip this step):

# cp website.key client.key.orig
# openssl rsa -in client.key.orig -out client.key

Create a certificate signing request and sign it with the root CA certificate:

# openssl req -new -key client.key -out client.csr
# openssl x509 -req -days 3000 -in client.csr -CA root_CA.crt -CAkey root_CA.key -set_serial 11 -out client.crt

Next you need to create a PKCS#12 file containing the cert and key:

# openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12

Set and remember the password because you’ll be asked for it when you import it into your browser or key chain. You may need to import the root certificate into your key chain too.

Time to configure the web server. I’m using nginx so here’s the config to force mutual authentication:

# HTTPS server
server {
listen 443;
access_log /var/log/nginx/;
error_log /var/log/nginx/;
root /var/www/;

ssl on;
ssl_certificate /etc/ssl/;
ssl_certificate_key /etc/ssl/;
ssl_client_certificate /etc/ssl/rootCA.crt;
ssl_verify_client on;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;