Monday, September 8, 2008

Simple Lesson on Secure Cookies

I recently read a paper written by Sandro Gauci from Enable Security entitled "Surf Jacking - HTTPS will not save you". You can find the paper here.

It's an interesting read and extremely relevant to today’s web applications.  The heart of the paper describes some simple tricks to force a session cookie to be sent over a non encrypted channel.  These tricks are possible if the secure flag isn’t set for the session cookie. These types of attacks have been discussed before. Side Jacking is probably the most well known (and most widely used) attack against leaked cookies.

<RANT> It bugs me that we’re still dealing with issues like this.  Despite having a simple and effective means to ensure that session cookies are only sent over secure channels, application owners choose to ignore the secure (and HTTPONLY) flag when developing their applications.  Later, as the application matures, developers find that their application has taken a significant dependency on this insecure behavior and what was once a simple fix now becomes a huge design change (which equals $$$).  The true victim's to these poor security decisions are the users who are left scratching their heads when their accounts get pwnd while using the WiFi at Joes Coffee shop. </RANT>

I believe the secure flag is symbolic of the current state of web application security… the countermeasures to the issues we are facing are known, simple, and effective... yet we continue to struggle on wide scale implementation because we've taken dependencies on insecure behavior.  SSL certs are another great example of this.  Every major browser has a way to bypass the security provided by SSL certs.  Browsers MUST offer this bypass because if they didn't, it would break the web... but i digress.

There is a bright spot when it comes to the protecting cookies.  Cookies are stored and protected by the browser (as any decent web app hacker should know!).  So, when an application server issues a "SET-COOKIE" header, it's merely a recommendation as to how the browser should use the cookie.  Each cookie is maintained by the browser and all the flags (secure, path, domain, httponly, expires...etc) associated with cookies are enforced ENTIRELY by the browser.  So, if an application server sets a cookie WITHOUT the secure flag, I can tell my browser to disregard the servers recommendation and add the secure flag which ensures that the cookie will only be sent over secure channels.  This is really simple stuff, so seasoned web app hackers can stop here. Everyone else can continue reading.

I've set up a page on here that simply sets a cookie in the following manner:

Set-Cookie: XSSniper=BKRios; expires=CURRENTDATE

Examining the Cookie in FireFox shows the following:

Bad Cookie!

As you can see, we have a cookie named XSSNIPER and the SECURE flag was NOT set by the server.  In fact, my server will NEVER set the secure flag for the XSSNIPER cookie.  Now if I want to force my browser to enforce the secure flag for the XSSNIPER cookie, I can do so by entering the following Javascript into address bar.

javascript:var cookies=unescape(document.cookie);var split=cookies.split(";");for (i = 0; i <split.length;i++){document.cookie=split[i]+";expires=Thu,1-Jan-1970 00:00:00 GMT;";document.cookie=split[i]+";secure;"}document.location="http://xs-sniper.com/blog";

The Javascript above expires all of the current cookies (only on the client side, if you had a session established with the server it would still be maintained) and sets every cookie for the current domain to secure.  I realize the Javascript is pretty ghetto, this should ideally be handled by application, but we could also use a browser plugin with a nice UI and fine grained control over each cookie attribute... Hmmmm a tool to prevent Surf/Side Jacking attacks... I wonder what I would call it... Any ideas Nate?

After we run the Javascript, we can take another look at the Cookie info presented by Firefox:

Secure Cookies for everyone!

As you can see, the cookie will only be sent over encrypted connections and the cookie now expires at the end of the session (no more persistence).  We've turned the XSSNIPER cookie into a SECURE cookie, despite the fact that the server never specified this behavior.

Now, this approach does have it cons... Servers typically recommend a particular cookie setting because the application was designed to work/anticipate/depend on those characteristics.  This will probably break some application functionality, but broken functionality will show you exactly where your cookie would have been leaked :)

10 comments:

  1. "we could also use a browser plugin with a nice UI and fine grained control over each cookie attribute…"

    The Firecookie add-on can be used to edit cookies and set them to secure.

    ReplyDelete
  2. MikeA: I use Firecookie, too.

    I used to use Add N Edit Cookies. I still use CookieCuller to mark cookies as protected (for ones that I want to keep around a long time). Although setting cookies as secure doesn't have the same feeling if I have to do it manually.

    Billy's method is neat (especially if automated with Technika) and gave me some new ideas. Rock on!

    ReplyDelete
  3. Yes, yes and yes. Great stuff, thank you.

    I'm working on a few Greasemonkey scripts (to be ported to an extension later on) for just this very thing.

    My first visit to your site, but based on this, you're a bookmarked regular now. Many thanks brother.

    ReplyDelete
  4. After playing around with .google.com, www.google.com, and mail.google.com cookies - it appears that one or all of the apps will still set an unencrypted SID cookie for .google.com. Sigh.

    I am going to stick with my old methods of doing things, which basically is "never go to a Google domain of any kind unless it's SSL - when I'm authenticated to any Google application, especially GMail".

    As an example, GMail is marking this cookie without the secure flagh
    gmailchat=username@gmail.com/111111

    ReplyDelete
  5. @Andre Gironda: I don't think you understand the vulnerability caused by insecure session cookies. Even though you are restricting your own navigating to HTTPS-only, it is amazingly for an attacker to force your browser to send your cookies over an insecure connection (non-HTTPS). That's why it's so big a problem.

    For example, to force a browser to leak all of its Facebook cookies, insert an image tag like this into ANY web page your browser loads ANYWHERE:


    Now that the attacker has read the session cookies that you've leaked, he can simply copy them to his own browser and browse away as if he were you.

    (Facebook was used as a simple and well-known example target. Obviously this has security implications far beyond Facebook, most worryingly for banking and other financial websites.)

    ReplyDelete
  6. Sorry, example HTML got stripped out of my comment. The image tag would look like this:

    {img src="http://www.facebook.com/favicon.ico"}

    where { and } are replaced by less-than and greater-than symbols

    ReplyDelete
  7. I completely agree with this article. However, I would like to point out that the fact that browsers have to provide a bypass for certs is in part due to the fact that some websites don't do their certs right or let them expire - and yes, without the bypass, it would break the web. I just wanted to make sure that we acknowledge that the cert issue is due mostly to laziness on the part of the website admin.

    ReplyDelete
  8. Forcing the web browser to automatically store every cookie set from an https domain as a secure cookie, seems to be the best option. But I am unable to locate a plugin that automatically does this. Will look around a bit more!

    ReplyDelete
  9. "the application was designed to work/anticipate/depend on those characteristics. This will probably break some application functionality, but broken functionality will show you exactly where your cookie would have been leaked"

    Are you referring to the fact that some web apps depend on cookies that the user would have then marked as secure only and therefore the server would not get/use them since the server is not using SSL at points when they "should"? If so, perhaps a useful tool would be one that can keep track of which cookies break functionality (community-updated database?) when marked secure, and mark all others as secure.

    ReplyDelete