Cookies don't replace Sessions
I've seen several instances where people have demonstrated the ease with which encrypted cookies can replace sessions within PHP. Michael Nitschinger wrote a piece recently demonstrating the switch with Lithium, while CodeIgniter does this by default (optionally encrypting). The problem is that while replacing sessions with cookies works, it introduces a few risks not present with native session support, and these risks tend to be under documented.
Encryption is often viewed as a panacea for security problems, you sprinkle a little encryption dust around, and your problems dissolve. Unfortunately, while properly implemented encryption solves the problem of other people reading your encrypted data quite well, it doesn't do much else. It doesn't (on its own) tell you if other people have duplicated your data, manipulated the data in question, or handed you an old copy of properly encrypted data.
Consider an attacker who manages to sit in between Amazon and one of their warehouses. Amazon (in this theoretical example) encrypts all order instructions well, then transmits them to the warehouse. The warehouse decrypts the instruction, fills the order, and ships. If the attacker wanted free stuff they could place an order during a low traffic period, and wait for Amazon to send an encrypted message and make a copy. A few minutes later they could re-send that encrypted message to the warehouse, never having even tried to read it. With luck, they'll soon receive two of whatever they just ordered! This is an instance of the replay attack, and that vulnerability is the one this post will examine in detail.
Exploiting cookie based sessions
Executing a replay attack against a cookie based session is easy, legitimately obtain some desired state on the system in question, and make a copy of your cookies. Should something go wrong, simply restore your cookies to the previous state. To demonstrate this, I've created a sample gambling application, you can get the source from github, or Play Now! (thanks to Orchestra.io, it's a free account so give it a moment)
In the game you start with $1000, then have the ability to make arbitrary wagers. Make a few bets to get a feel for the system, then make a copy of your cookie values. Bet again. If you lose money, simply restore your earlier cookies to get that money back. That's it. This attack works because the system is willing to accept any successfully decrypted message as a valid, and current, session.
This attack doesn't exist under traditional session storage. The user's cookie doesn't change from one request to the next as their money goes up and down. If a system is regenerating the session ID when the user changes privilege levels, the old session is deleted and no longer available when invoked properly:session_regenerate_id(TRUE);
A system using cookie based session storage, while using a CAPTCHA to defeat bots is doomed to fail, the attacker could solve the CAPTCHA once, then re-use that same cookie a million times. Encryption makes it difficult for an attacker to read the message, additional systems must be bolted on to defend against this sort of attack. In the stateless world of HTTP and the web, this is exceedingly difficult without some server-side datastore.
While this was clearly a trivial example, the problem is not. If you're looking at using cookie based sessions it's one of the things you need to be aware of.
If you're interested in learning more about cryptography, including a great rundown of this problem and many others, I'd highly recommend Practical Cryptography