For those arguing about whether cookies are good or bad, be aware that this problem is larger than just cookies. This vulnerability comes into play with any kind of authentication where
- the continuing authentication is automatic (requiring no additional user interaction), and
- sensitive actions have well known or predictable URLs.
For the authentication part, the two most common techniques (cookie-based and HTTP auth) are both automatic; which means that subsequent HTTP requests continue with the same authentication without requiring any HUMAN interaction. Lesser used techniques such as browser-side SSL certificates also have this property. So it’s not just cookie-based logins that are vulnerable.
Note there is another technique transmitting authentication credentials, URL munging (inserting some secret credential token in all URLs), which may or may not have this automatic property depending on how carefully its used. The URL munging approach though has many challenges of its own, such as leaking credentials via offsite links with referrer headers, interference with browser history, and not being RESTful, etc.
For the second part, the URLs must be predictable or guessable. If you’re building a RESTful site, this unavoidable. Of course if you dispose of REST, and bookmarking, and lots of other good webby features; you can randomize your URLs. That will be quite effective at thwarting these attacks.
As mentioned, the double cookie solution works because it effectively randomizes the URL, especially in a GET. Yes, in a POST the randomness is not technically in the URL, but effectively it is still part of the identity of the resource being accessed. But also think of methods like PUT and DELETE (which can be invoked with Ajax); those can’t easily be protected using the double cookie method without some unusual effort (such as URL munging, or perhaps sending extra non-standard HTTP headers to transport the second validation code/cookie copy).
Another idea, especially for super-sensitive operations, is to use a captcha in your forms. This will effectively neutralize the automatic authentication, by forcing the user to interact with the request. It doesn’t even have to be a strong captcha, just as long as its value is random.
This is a very hard problem to solve; it is easy to underestimate all the attack vector variants.