Selective SSL

Ever tried to selectively enable certain pages/set of pages with SSL? Found the ride bumpy :) and ended up bruised? Typically, you need to do this anytime you’re exposing private information. The usual candidates are the login form, any credit card payment form, a user profile page where the user puts in info that may be considered private (home address, phone etc) – you get the idea. Enabling ssl globally may be an option if you have a HLB of offload the SSL connection overhead – but generally, its far better to selectively enable SSL for portions that really need it. You could also get away with it if you have strict control over user behavior – say you always force the user to login before doing anything else at all. But typically, this is not the case in internet facing sites. Here’s a bunch of use cases for a typical internet storefront which has a bunch of catalog and product pages (non-ssl) and certain protected areas (login, checkout CC payment, order history etc):

  1. browse product pages (http), add a few items to his cart(http) and decide to checkout (https)
  2. have bookmarked his order receipt page (https). Later when he clicks the link, he must be taken to login (https) and then taken to his receipt page. He could, of course, decide to continue shopping later, in which case, his session must be carried over when he goes to the non-ssl product/catalog pages.

Note that the solution applies to Apache Tomcat 5.5. I’m currently enamoured with Tapestry – so the code I wrote to test this all out is Java and the Tapestry framework – but the issue is more conceptual and would apply to pretty much any web/app server and any programming language. Assuming your login page is /myshop/login.html, you could of course try the following:

  1. Set up your deployment descriptor to ensure that the url /myshop/login.html is always SSL.
  2. Configure your website (with a filter etc), so that whenever someone requests a protected resource, the filter checks to see if a valid user exists in session. If there is an authenticated user, you could check any authorization rules and then allow access to the resource. If there isnt an authenticated user, you should redirect the user to the login page, after saving the originally requested url somewhere (typically, in the request object as the nexturl), so that after login, you can send the user back to his original destination.

Depending on your web/app server, framework, language and browser, you might find that this works just fine – in which case you wouldnt be reading this in the first place :-). More likely, you’ve found that after https login, if you go to a plain old http page, you’re application seems to have forgotten you altogether. Also, you’ve found that the whole thing seems to work on and off – as in, based on how much and where you’ve navigated across your site, the session may or may not carry over when you switch from HTTPS to HTTP.

What’s going on?

Stuff you already knew

So what’s going on? Well, its the way browsers and web servers handle security and you will need to understand HTTP/1.1 works. The following list is stuff you already know:

  1. HTTP is stateless. However, web applications track sessions with a cookie which contains a unique session id (JSESSIONID in the java world).
  2. Maintaining sessions at the server end imposes an overhead. Its a best practice to defer session creation until absolutely needed.
  3. Once the web server sets a cookie, browsers will re-send the cookie with each request to the server.

Stuff that’s leading to seemingly insane situation

  1. Web/App servers may mark a cookie as secure. In this case, the browser will resend the cookie with the request if and only if the request is on HTTPS.
  2. If a session is created during a secure request, the session cookie will be marked secure. If a ‘normal’ session already exists during a secure request, the session cookie will be added to the session.

Those two details should clear up the fog :-). Note that point 2 above is with respect to Tomcat 5.5. You should check up your server.

A Strategy

Each secure page that needs access to the session must implement a validation routine. The routine checks if the request is https and has a session already. If not, we redirect to a http url where we initialize the session and then come back to HTTPS. This ensures that when the login page is displayed, there’s always a session available.

	public void pageValidate(PageEvent event) {
		System.out.println("In PageValidate of login page");
		if (!getRequest().isSecure()) {
			//HTTP
			if (!isUserInSession()) {
				//force session creation.\
				System.out.println("Force session creation");
				getRequest().getSession(true);
			}
			String currentUrl = getAbsoluteUrl();
			String httpsUrl = getHttpsUrl(currentUrl);
			throw new RedirectException(httpsUrl);
		} else if (!isUserInSession()) {
			//https but no session - go back to http
			String httpUrl = getHttpUrl(getAbsoluteUrl);
			throw new RedirectException(httpUrl);
		}
	}

Note that there isnt much dependency on the page itself – so you should really take this all out to a utility function or a request filter.

What about session-hijacking

Note that if someone has access to your session id, then they could essentially get the same level as access as you have. And its not that hard to do either – if your site is XSS vulnerable, then all it takes is for someone to inject a bit of javascript to pass out your session cookies to a different (malicious) server. Or the attacker could just monitor HTTP traffic to your server and sniff out your session cookies. In fact, here’s a step-by-step to get into someone’s gmail account :-). I think this has been plugged now by google, but quite recently was in the news. You should really go on full SSL on your gmail if you don’t already do so!

More follow up needed

  1. Setup for web server (apache) fronting tomcat/app container
  2. In the worst case, we end up doing three redirects (when the user comes to https login page without a session – first to http to force session creation and then back to https for displaying the page.) Add to this that we will also redirect after login to the originally requested page. That is’nt very nice – so I’d be keen to hear if someone has a better idea.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s