This past week, I posted a note here about a new Firefox extension called FireSheep, which is designed to automatically eavesdrop on public wireless networks, and to capture session identification information included in browser cookies. As I mentioned in that post, the cookie mechanism was grafted onto the Web, as a way of introducing the concept of sessions, with at least temporarily persistent state, on top of the stateless HTTP protocol.
I have just come across an interesting blog post, by Michal Zalewski, a security researcher, that gives an overview of the development of the cookie mechanism, and points out some of its inherent problems. (Mr. Zalewski is also the author and maintainer of the Browser Security Handbook, available at Google’s code site.) The first cookie mechanism was implemented in the Netscape (remember them?) Navigator browser by 1995. Although the idea was quickly copied by other browser developers, it would be a couple of years before the first attempt at a formal specification was made, in RFC 2109.
The document captured some of the status quo – but confusingly, also tried to tweak the design, an effort that proved to be completely unsuccessful; for example, contrary to what is implied by this RFC, most browsers do not support multiple comma-delimited
NAME=VALUEin a single
Set-Cookieheader; do not recognize
quoted-stringcookie values; and do not use
max-ageto determine cookie lifetime.
Browser makers continued to make their own “improvements” to the mechanism. Three years later, another attempt to set a standard for the cookie mechanism was made in RFC 2965. As an attempt to establish standard behavior for browsers, this attempt was also notably unsuccessful.
All these moves led to a very interesting situation: there is simply no accurate, official account of cookie behavior in modern browsers; the two relevant RFCs, often cited by people arguing on the Internet, are completely out of touch with reality.
This led to a situation, which to a significant degree still exists, in which Web developers had to try to infer the rules by which cookies were processed by experiment.
In addition to the session hijacking risk that I outlined in that earlier post, the use of the cookie mechanism introduces other risks. Clearly, since the values carried by the cookie have to be stored somewhere, both at the server and the client, there is some finite limit on the amount of information that can be stored. In addition, servers typically limit the size of the requests they are willing to process, in order to make mounting a denial-of-service attack a bit more difficult. And there are limits to how much information the client browser can store. Unfortunately, there are not any generally recognized safe limits for the size of these objects, and the limits that do exist do not suffer from any “foolish consistency” (according to Emerson, the “hobgoblin of little minds”).
For example, the later RFC 2965 standard specifies that browsers should support cookie sizes of at least 4096 (4K) bytes, and at least 20 cookies per host. That works out to 80K per host, considerably in excess of what real servers will typically accept (for example, Apache servers will typically not accept requests longer than 8K). The standard also allows for the use of characters from extended character sets, but does not specify any particular method of encoding them. In the face of such fuzzy standards, developers have often taken the path of least resistance, to the detriment of browser security.
There are many more examples of problems in Mr. Zalewski’s post. Cookies are another example, it seems, of what is apparently the mantra of Internet technology: “There’s never time to do it right, but there’s always time to do it over.”