Monday, August 5, 2013

How to Securely Communicate with a Non-Secure Server

Security is a very important consideration when building web applications. In order to build trust with your client, they need to know that their information is not going to be compromised. Obviously the best practice is to have the application installed on a server that has a good SSL certificate and the application is only accessible via HTTPS. This is all well and good if you're building an application that will run on a server that you control.

But what if you're building a distributed web application that will be installed by your customers on their servers? I've found that the end clients are, in general, not very savvy when it comes to server setups and they have to be walked through every step. Adding additional requirements or steps to the installation process can just make their head spin. Obviously there are clients out there that are very security conscience and tech savvy and either already have a secure server or know exactly how to set one up; they are much easier to deal with.

Getting down to the nitty gritty, the most important items to protect from snoopers is login credentials. But how do you do this when credentials are being transmitted over a non-secure connection to their server because their server doesn't support HTTPS?

One option is to build your own encryption method. This is rather much of a false sense of security. While the actual information being transmitted is not plain text, it is typically very easy to decipher. I've employed character remapping, usually adding salts, techniques to do this. The two big downfalls of this method are that you are transmitting the key when the page loads and it's a fixed remapping so, for instance, t always equals Y.

Another option is to use a client side encryption schema that can then be decrypted by your application. Javascript plugins, such as SJCL or jscrypto. The problem with any encryption that happens on the client side is that the server has to transmit everything that is needed to encrypt the data, and in turn everything that is needed to decrypt the data. There are ways of getting around the inherent security issues, just look at how Braintree does it. But this is not easy or quick.

The best option if you have a secure server at your disposal, say for client authentication to make sure that your client still should be allowed to use your product, is to send critical communications to that server instead. The principle works like this. Because any communication sent over HTTPS is secure by nature, all you have to do is make sure that all sensitive communications are being routed through your secure server. So in practice, you can have the browser send credentials to the secure server via JSONP (to the HTTPS address) or simple form data. The JSONP is a much more user friendly method in my opinion. The secure server then stores the credentials temporarily (maybe as long as five seconds). Once the secure server has the information, it sends a signal back saying I got the information, you can proceed. The browser then sends a signal to their non-secure server to get the credentials from your secure server. This is done via a cURL request in PHP. Again because you are sending the request to the HTTPS address of your server, the entire communication is encrypted. Your server sends back a json encoded response for instance. So now their non-secure server has the credentials to do what every you need it to do and they were never sent over a non-secure connection.

I wouldn't recommend sending all communications through you server because of the extra traffic, but for login's and changing credentials, the hit wouldn't be that bad.

Your server can either store the credentials in a database or memory via APC. Either way, as soon as their server requests the credentials, wipe them from your server. You don't want to store unencrypted credentials on your server, it's just asking for a disaster.