The behaviour of web browsers for the HTTP protocol can be different from the way they work with HTTPS. Notably, when you include a resource in your page that is acquired via an HTTP link, it won’t load when you serve that same page via HTTPS. This means that a page that works fine in your unsecured development environment may become broken when you deploy it to any server that is secured with an TLS/SSL certificate. If you want to catch such errors before they become a problem, the most obvious solution is to use TLS/SSL in your development environment too.
However, apart from the technicalities, there is the very real and practical objection that your customers will be reluctant to make availabe to developers the same SSL certificate that is used for the production server. After all, such a certificate is a proof of identity amongst other things, and access to it should be limited.
This article is accompanied by a working demonstration project. See link at end of text
Fortunately, it turns out you can create your own fake SSL certificate while impersonating your customer. And with some tweaking, you can get the browser(s) on your development machine(s) to accept these fake certificates as the real McCoy. Problem solved!
In this article I will explain how to create and use such fake certificates.
TLS and SSL
Transport Layer Security and Secure Socket Layer both are protocols that create a secure connection between a webbrowser and a server. TLS is the newer of the two and all major browsers prefer it over SSL. The objective is two-fold:
- Ensure that the webserver you are accessing is operated by the legitimate owner of the domain.
- Encrypt traffic between server and browser.
Both of these things are accomplished with the aid of a so-called TLS/SSL certificate, which the server sends to your browser upon first contact. This file contains a “notarized” statement of identity for purpose(1) and a public encryption key for purpose(2). Note that both TLS and SSL are able to use the same certificate. Which of the two protocols will be used in a particular session is established by a handshake between server and browser which happens when the connection is initially set up. The handshake also takes care of myriads of other details such as what encryption algorithms to use, exchange of public keys and so on. Here are some more details on the handshake.
As for the notarized statement of identity contained in the TLS/SSL certificate file, this relies on the fact that the notary who vouches for the servers identity is known to and trusted by the browser. In terms of TLS/SSL the notary is called a Certificate Authority (abbreviated CA) and the browser has a built in list of such CA’s in the form of CA Root Certificates. When the browser initially receives the certificate from the server, it extracts the CA and looks it up in the list.
How do I set it up?
Now, how does the above explanation translate into practical terms? I have a webserver running locally on port 8080 and I want to make it work with an TLS/SSL certificate. What do I need to do?
- Obtain a server certificate
- Start using a frontend server program that is able to handle TLS/SSL such as Apache or NGinx
- Install the certificate in the frontend configuration and redirect traffic to http://localhost:8080
In the above, the frontend server program sits as a passthrough translator between http://localhost:8080
and the browser. It takes care of all details of decryption and encryption. You application listening on port 8080 receives unencrypted requests and sends unencrypted responses.
Frontend servers such as Apache and NGinx can do a whole lot more than just encrypt and decrypt messages. They can add and remove HTTP headers, rewrite the URL of a request and of course log a ton of information for each exchange that passes through. One important ability is to redirect traffic for a certain URL to another one. In this way we can send requests from our browser to any URL, and, provided that DNS points the host part of that URL to the IP address of our development machine, catch these requests and redirect them to http://127.0.0.1:8080 where an instance of the web application is running in debug mode in the IDE.
Configuring the frontend webserver is not for the faint of heart: with great ability comes great complexity. This documentation provides a step by step example for Apache. You will also need to add entries to your local DNS configuration to make some of the URLs that you type in the addressbar resolve back to your local development machine. Rackspace explains how to go about this.
So, how do I obtain a TLS/SSL certificate?
This entails the folowing steps:
- Create a private/public key pair for encryption by the server.
- Create a request for signing (CSR).
- Find a CA willing to sign your CSR.
For step 1 and step 2 many resources on the Internet will tell you that you need to use a tool named openssl. While this is valid advice and openssl is indeed a powerful command line utility, the very fact that it can do many things and has many options and settings makes it somewhat intimidating for the casual user. Instead, I would like to direct your attention to XCA . This is a free program that runs on Windows, MacOS and linux, has a nice UI and does all of the things we need. In addition it is well documented.
When dealing with a real life CA, step 3 is usually done by submitting the CSR together with proof of ownership for the domain plus a fee and then waiting impatiently for the signed certificate to arrive in your mailbox. When creating a fake certificate, you yourself act as the CA and sign the request, resulting immediately in a certificate file.
Actually, for fake certificates, there are two paths you can choose. The shortest path is to skip the CSR part and create a certificate immediately from the public/private key pair and the information about your domain. This results in a so-called self signed certificate which does not rely on any CA whatsoever but simply states “I am valid”.
Alas, your browser is not fooled and will inform you it has received an untrusted certificate. You can then tell the browser to trust it anyways and serve the website. Most browsers will comply but at the same time not trust the certificate completely, which can lead to subtle problems.
Therefore I recommend using the other way of creating a self signed certificate, which is to create your own fake CA and then use that for signing a normal CSR. In that case, you need to import the CA Root certificate for your own fake CA into the list of of CA’s that the browser knows and trusts, and then your fake server certificate signed by the fake CA will be trusted like any other.
The exact details on how to import a fake CA Root certificate vary by browser and by operating system. Here is a pretty good guide.
Important When you create a self signed certificate, or sign a CSR with your fake CA Root certificate, make sure to fill in the Alternate Common Name field too. If you don’t, Chrome will refuse to acknowledge the validity of the certificate, see here.
Also important When you are working locally on client applications that make requests to a local running instance of your webserver, they will run into the same distrust issue that your browser did. You can fix this by importing the server certificate into the keystore of the JVM. You can use the keytool
utility included with the JVM, or take the easy way and use Key explorer.
Further details and considerations
Both methods (self signed and fake CA) for signing a certificate are fairly easy to do using XCA, see the cheat sheet.
You can easily create a fake certificate for a domain instead of for a single url, by simply using *.acme.eu in the CN and in the alternate CN name fields instead of filling in the whole server name such as local.acme.eu . If you worry that this conflicts with a real domain certificate for the same domain in production, the answer is no. I tested it. You can trust me on this.
The browser cache is not your friend! As it turns out, your browser may or may not continue serving stale content from its cache. It happenend to me when, after correcting errors in the Apache configuration, I requested the exact same URLs that previously caused an error but now should work. The browser saw an unchanged request and decided to not bother the server, resulting in the same error page that I got before. I only noticed after using curl
to find out what was going on with all the recursive redirections it kept complaining about. curl
doesn’t cache results ands gives you the reply straight from the servers output stream. As an alternative, try your browser in incognito mode.
And last but not least, I have made a small demonstration project that uses a fake certificate to serve both a website and CMS from two made up URLs that point to your localhost. The project is a Bloomreach webapp and the source includes all the necessary configuration, a set of fake certificates and detailed instructions on how to set it all up on your development machine. You can find it here: