Using https with stunnel and ssl_wrapper

Whilst randomly wandering around GitHub a few weeks ago, I noticed ssl_wrapper, which I thought was interesting. Actually, I quite liked the idea of moving the https stuff into a seperate module. It means that any vulnerabilities found in the SSL/TLS stuff could be patched without having to do anything to the actual web server. I am also a fan of the philosophy of smaller pieces of code which can be well tested independently. I suppose this is just the Unix philosophy. But whatever you call it; I liked the idea.

So I had a bit of a play with ssl_wrapper, and even forked the repository to make the basic instructions a bit easier for me to follow, including the creation of a certificate for testing.

So I tried it out by running my own CPU Monitoring webserver over an https connection. However, in Chrome, I noticed that Google considers it to be using 'obsolete cryptography', like this:

I know that Chrome says this about a lot of existing sites, but I thought that it would be a good idea to try and make that message go away. But so far, I have not managed to do that with ssl_wrapper. In the meantime, I have logged an issue on GitHub.

UPDATE: this has now been fixed (but not by me, by the original authors). You can use ssl_wrapper and Chrome will say you're using 'modern cryptography'.

But since I was now interested in all this stuff, I decided to go and look and see if there are alternatives. Indeed there are, and a good one is stunnel. On my Ubuntu box installing it was a breeze, like this:

sudo apt-get install stunnel4

NOTE: I found that it is sometimes important to refer to stunnel4 with the '4' at the end, because your machine might already have an older version.

I was able to take the same certificate I was using with ssl_wrapper and set it up in stunnel. But straight away I found that Chrome was happier, and declared that I was using modern cryptography, like this.

Nice! Another advantage of stunnel is that there has been more recent activity on maintaining the code, which is somewhat comforting.

So, I am now setting up a seperate GitHub repository to help me to test stunnel on various Linux boxes (I have yet to try it on my Rasperry Pi, for example). It means I can be lazy and do this:

sudo apt-get install stunnel4
git clone https://github.com/davidsblog/stunnel4_config
cd stunnel4_config
sudo make

Which is a pretty painless way to test it out on different machines.

More fiddling with MVC3 and https

I blogged here about securing logon cookies in MVC3. After writing a custom attribute based on the [RequireHttps] attribute it turned out that the best way was to use the forms authentication properties in web.config instead.

But the custom attribute that I wrote ended up morphing into something that solves a different problem. When you use the [RequireHttps] attribute, you might notice that even when a user logs out they continue with an https connection on subsequent requests to your site. This is not a big problem, but I find it annoying since https is not needed anymore. A similar thing might happen if a user has accidentally bookmarked the https version of your site's homepage, in which case the encryption might be unnecessary.

So I changed my existing attribute class into the [LimitHttps] Attribute. It checks to see if you are using a secure connection AND are not authenticated, then switches you back to plain old http - unless you are visiting a route that requires https. This is how I'm using it:

1) add the [RequireHttps] attribute to Account\LogOn and Account\Register
2) set up forms authentication with requireSSL="true" in web.config
3) add this line to RegisterGlobalFilters() in Global.asax:
     filters.Add(new LimitHttpsAttribute());

You'll now find that the following things happen:

- https will be enforced when a user is logged in
  (this is due to the requireSSL property in web.config)

- if a user manually goes back to http, the login cookie will not be sent in the request
  (also due to the requireSSL property)

- The LogOn and Register views in the Account controller will always use SSL (https)
  (because we've added the [RequireHttps] attribute to them)

- when a user logs out, they will automatically revert back to http
  (which is done by the [LimitHttps] attribute we've added)

- if a user visits the homepage with https they will switch back to http
  (the [LimitHttps] attribute does this too)

The code can be downloaded by clicking below.
Download the [LimitHttps] attribute

Security for login cookies with ASP.Net MVC3

I was reading here about how it's a bad idea to log into your application using SSL (https) and then revert back to http for subsequent pages. If you do that then you'll send the authentication token over an unencrypted connection, which is a bad thing.

Whilst wondering if there was an easy way to solve that problem, I wrote some code to try and enforce a secure connection whenever the user was authenticated. So I wrote my own [RequireHttpsWhenAuthenticatedAttribute] which inherited from [RequireHttpsAttribute]. The idea was that you apply it to your whole site from your global.asax, and then https will *automatically* be turned on (and enforced) when users are logged in.

After posting that code, I got an e-mail from Andy Brown (thanks Andy) pointing out that if a logged in user switches to http by editing the address in their browser, the cookie will have already been posted back to the site by the time my new attribute is able to do anything. To be totally safe you'd have to assume that the cookie is already compromised at that point. I then realised that even if the site signs them out, the cookie could still be used by a hijacker until it times out.  For example, this article says “Even after the user has logged out of the application and the developer has called FormsAuthentication.SignOut, the authentication ticket remains valid until its time-to-live (TTL) expires, so it can be used by an attacker to impersonate another user.” 

So I went back to the drawing board to try and find an even better way.

In the end, the best option seems to be simply using this option when you set up forms authentication in your web.config:

requireSSL="true"

Rather than refer to your whole site, this attribute just applies to the authentication cookie, meaning the the browser should only send the cookie over https. Using that setting does the same job that my code was trying to do, only better. So I don't need any special code after all.