A Rough Guide to the Secure Cookie

On a recent pentest, I reported that the session management cookie was not being set with the secure flag (surprise, surprise)…

No secure flag

No secure flag

But in this case it didn’t seem to matter so much. Why? Because port 80 was shut: the whole application was served over HTTPS so the cookie would never have the chance to escape over HTTP, even if an attacker could engineer such a scenario – for example, by enticing the victim to click on a HTTP link (although more on this shortly). This is because the TCP connection must be set up with the 3-way handshake before any application data is sent over it – and since the port was closed, the connection falls at the first hurdle [1].

Nevertheless I still reported the missing secure flag because the application was in a test environment and what if port 80 was open on the live server? Now the cookie is more vulnerable. And there’s another consideration. While port 80 on the host under scrutiny (e.g. secure.example.com) was filtered, port 80 may have been open on another related host (e.g. test.secure.example.com or www.example.com). If the attacker used a HTTP link to another such host instead, then when the link was clicked, the cookie could be transmitted. You’ll notice a “could” there – it depends on any accompanying domain and path restrictions on the cookie when it was set (and possibly how the browser interprets them).

foo.example.com sets a cookie over HTTPS with domain=.example.com

foo.example.com sets a cookie over HTTPS with domain=.example.com

A request to bar.example.com over HTTP includes the cookie

A request to bar.example.com over HTTP includes the cookie

The classic protocol-host-port tuple of the Same Origin Policy (SOP) doesn’t apply to the scoping of cookies. If it was, we wouldn’t need the secure flag because, assuming the cookie was set as secure over HTTPS, the request over HTTP would be a change of protocol and port, so it wouldn’t be transmitted. Cookie security pre-dates SOP as we know it (or sort of know it!) and its definition of “same origin” is different. I recommend Michal Zalewski’s Browser Security Handbook or his book The Tangled Web for more details, then fire up your web proxy and experiment!  And it was while doing just this that I discovered another side to the secure cookie.

I was testing the rules applied to JavaScript’s access to cookies (as opposed to the rules applied to transmission). I normally think of httponly as the principal attribute governing access to cookies by JavaScript but that’s not so. The domain and path attributes also play a part so that the browser’s policy for cookie access by JavaScript mirrors the transmission policy, which makes sense when you think about it. For example, if a cookie was set with the domain restricted to foo.example.com, it wouldn’t be transmitted with a request to bar.example.com so why should JavaScript from bar.example.com be able to access that cookie?

For the same reason, the secure flag also has a role in determining JavaScript’s access to cookies. I found that a cookie set as secure but not httponly was inaccessible to JavaScript delivered over HTTP from the same domain and path. This was independent of whether the cookie was set over HTTP or HTTPS. Again, the reason is because the cookie would not be transmitted under those conditions.

This all makes complete sense, it’s just that I’ve not seen any reference to this behaviour in the likes of the Web Application Hacker’s HandbookThe Tangled Web or the cookie RFC 6265. I guess it’s just implicit from the specification but sometimes it’s not until you think things through that the implicit becomes obvious! One thing to note, though, is that although the HTTP-delivered JavaScript could not access the secure cookie, it could overwrite the cookie – what’s known as “clobbering”.)

Incidentally, Internet Explorer 10 seems to have corrected the bug noted in the Browser Security Handbook:

There is no way to limit cookies to a single DNS name only, other than by not specifying domain= value at all – and even this does not work in Microsoft Internet Explorer…

It appears this statement covered IE versions 6, 7 and 8. Well, I can’t speak for 9 but with IE10 I noticed that a cookie from foo.example.com with no domain attribute wasn’t later sent to example.com.

To finish off, remember that you can only set the secure flag if the application is designed with this in mind since any HTTP request will be missing cookies that have been set as secure. An obvious side effect of this, for example, could be that the newly authenticated session management cookie set over HTTPS is withheld over HTTP, effectively logging off the user. Of course, whether or not the application should revert to HTTP following secure authentication is another matter!

===== UPDATE =====

[1]   Dafydd Stuttard, aka PortSwigger, pointed out a neat bypass using the link http://www.example.com:443. Now the TCP connection succeeds and the browser sends the HTTP request. The SSL connection will of course fail but it’s too late, the session management cookie has gone up in the plain text request. (This is why he wrote the Web Application Hacker’s Handbook and I didn’t.) He also noted that since the attacker is in a position to sniff, having seen the SYN to port 80, the SYN/ACK could be spoofed in order to trick the browser into thinking the port is open. Thinking about this further, in an open Wi-Fi network the attacker could do this without even being an active man-in-the-middle using the Airpwn principle.

Leave a Reply

Your email address will not be published. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>