Session cookies for web applications
Two weeks ago on this page, we reported on some Wordpress vulnerabilities that were caused by incorrectly generating authentication cookies. The article was a bit light on details about such cookies, so this follow-up hopes to remedy that. In addition, Steven Murdoch, who discovered both of the holes, recently presented a paper on a new cookie technique that provides some additional safeguards over other schemes.
HTTP is a stateless protocol which means that any application that wishes to track multiple requests as a single session must provide its own way to link those requests. This is typically done through cookies, which are opaque blobs of data that are stored by browsers. Cookies are sent to the browser as part of an HTTP response, usually after some kind of authentication is successful. The browser associates the cookie with the URL of the site so that it can send the cookie value back to the server on each subsequent request.
Servers can then use the value as a key into some kind of persistent storage so that all requests that contain that cookie value are treated as belonging to a particular session. In particular, it represents that the user associated with that session has correctly authenticated. The cookie lasts until it expires or is deleted by the user. When that happens, the user must re-authenticate to get a new cookie which also starts a new session. Users find this annoying if it happens too frequently, so expirations are often quite long.
If the user explicitly logs out of the application, any server-side resources that are being used to store state information can be freed, but that is often not the case. Users will generally just close their browser (or tab) while still being logged in. It is also convenient for users to be allowed multiple concurrent sessions, generally from multiple computers, which will cause the number of sessions stored to be larger, perhaps much larger, than the number of users.
Applications could restrict the number of sessions allowed by a user, or ratchet the expiration value way down, but they typically do not for user convenience. This allows for a potential denial of service when an attacker creates so many sessions that the server runs out of persistent storage. For this reason, stateless session cookies [PDF] were created.
Stateless session cookies store all of the state information in the cookie itself, so that the server need not keep anything in the database, filesystem, or memory. The data in the cookie must be encoded in such a way that they cannot be forged, otherwise attackers could create cookies that allow them access they should not have. This is essentially where Wordpress went wrong. By not implementing stateless session cookies correctly, a valid cookie for one user could be modified into a valid cookie for a different user.
A stateless session cookie has the state data and expiration "in the clear" followed by a secure hash (SHA-256 for example) of those same values along with a key known only by the server. When the server receives the cookie value, it can calculate the hash and if it matches, proceed to use the state information. Because the secret is not known, an attacker cannot create their own cookies with values of their choosing.
The other side of that coin is that an attacker can create spoofed cookies if they know the secret. Murdoch wanted to extend the concept such that even getting access to the secret, through a SQL injection or other web application flaw, would not feasibly allow an attacker to create a spoofed cookie. The result is hardened stateless session cookies [PDF].
The basic idea behind the scheme is to add an additional field to stateless session cookies that corresponds to an authenticator generated when an account is first set up. This authenticator is generated from the password at account creation by iteratively calculating the cryptographic hash of the password and a long salt value.
Salt is a random string—usually just a few characters long—that is added to a password before it gets hashed, then stored with the password in the clear. It is used to eliminate the use of rainbow tables to crack passwords. Hardened stateless session cookies use a 128-bit salt value, then repeatedly calculate HASH(prev|salt), where prev is the password the first time through and the hash value from the previous calculation on each subsequent iteration.
The number of iterations is large, 256 for example, but not a secret. Once that value is calculated, it is hashed one last time, without the salt, and then stored in the user table as the authenticator. When the cookie value is created after a successful authentication, only the output of the iterative hash itself is placed in the cookie, not the authenticator that is stored in the database. Cookie verification then must do the standard stateless session cookie hash verification, to ensure that the values have not been manipulated, then hash the value in the cookie to verify against authenticator in the database.
If it sounds complicated, it is; the performance of doing 256 hashes is also an issue, but it does protect against the secret key being lost. Because an attacker cannot calculate a valid authenticator value to put in the cookie (doing so would require breaking SHA-256), they cannot create their own spoofed cookies.
While it is not clear that the overhead of all of these hash calculations is warranted, it is an interesting extension to the stateless session cookie scheme. In his paper, Murdoch mentions some variations that could be used to further increase the security of the technique.
| Index entries for this article | |
|---|---|
| Security | Browser cookies |
| Security | Web sessions |
Posted May 22, 2008 15:56 UTC (Thu)
by i3839 (guest, #31386)
[Link]
Posted May 23, 2008 7:55 UTC (Fri)
by ekj (guest, #1524)
[Link] (1 responses)
Posted May 23, 2008 9:30 UTC (Fri)
by intgr (subscriber, #39733)
[Link]
Session cookies for web applications
> the performance of doing 256 hashes is also an issue, but it does protect
> against the secret key being lost. Because an attacker cannot calculate a
> valid authenticator value to put in the cookie (doing so would require
> breaking SHA-256), they cannot create their own spoofed cookies.
Mind that doing 256 hashes instead of a couple is to make it more work to guess the password,
so the only reason is to protect weak passwords, nothing else. Normally brute-force attacks
are made impossible by the salt (at other times than login), but when the attacker has read
access the salt is known.
As users don't login often, the overhead of doing 256 hashes shouldn't be noticeable.
Murdoch describes a simpler alternative that achieves almost the same as this more complicated
version at:
http://www.cl.cam.ac.uk/~sjm217/advisories/wordpress-cook...
> Potential fixes:
>
> The problem occurs because it is easy to go from the password hash
> in the database to a cookie (i.e the application of MD5 is the wrong
> way around). The simplest fix is to store MD5(MD5(password)) in the
> database, and make the cookie MD5(password). This still makes it
> infeasible to retrieve the password from a cookie, but means that it
> is also infeasible to generate a valid cookie from the database
> entry.
>
> However, there are other vulnerabilities in the Wordpress cookie and
> password handling, which should be resolved too:
>
> - Passwords are unsalted [2], leaving them open to brute force, rainbow
> table and other attacks [3].
> - It is impossible to revoke a cookie without changing the user's
> password.
> - Cookies do not contain an expiry time, so are always valid (until
> the user's password changes)
> - There ought to be an option to limit cookies to a particular
> IP address or range.
Adding a salt is simple. It would also fix his second point, because revoking a cookie is done
easily by changing the salt, although to do that the original password is needed. Or use a
different salt for the cookie hash.
The last point isn't handled by his new proposal either.
The third point, expiry time, is, but only while the attacker has no read access to the
database.
So the main difference is that MAC is used in addition to normal hashing and that expire-time
and salt are used in the hashing, but the principle is mostly the same.
Over all, the main advantage of stateless session cookies is that the server doesn't need to
access the database to know a client's rights. The problem of brute-force attack and
accumulating session cookies can be simply solved by not storing more than one (or a few)
session number per user. Protecting against read-only database access can be done by sending a
huge random value to the client and storing the hash result, instead of storing the number
directly. The cookie is totally decoupled from the user's password, which seems more secure.
With Murdoch's proposal the server still needs to access the database to get the user's
account details (because read access to the database is assumed, including the key used for
the MAC, so it could be forged), and then the advantages of stateless session cookies are
mostly gone.
Session cookies for web applications
This is pretty much a solution to a non-problem though.
There are -huge- problems in web-application-security for sure. Keeping A from being able to
impersonate B when A has complete read-access to the entirety of the database typically isn't
among them.
Get me right, in principle any improvement is a good thing. You'd be better off fixing
SQL-injection in the first place though, as this method primarily defends against that. And
it's not as if fixing sql-injection is difficult.
Session cookies for web applications
And it's not as if fixing sql-injection is difficult.
Fixing one SQL injection is not difficult. Finding and fixing all SQL injections in a legacy web application on the other hand...
