Understanding why CSRF protection really needs cookies
For reasons beyond the scope of this entry I've been thinking about adding some CSRF protection to the comment posting system here (which is the only thing that's exposed to CSRF attacks). My understanding is that the standard approach to CSRF protection is to set the same magic number as a cookie and as a hidden form parameter when you initially send the form to the user then reject form submissions when the two don't match. The problem with this, from my perspective, is that this needs you to accept cookies from Wandering Thoughts and I don't want to require that.
At first I thought I could get around this by using a hidden authenticator in the form, formed by a HMAC of various bits of information signed with a server secret. With appropriate protection I could prevent the attacker from getting the victim to make an initial form request and then reading out the hidden form field from it. This even half-works in that I could make it protect me (and a few other people), just not ordinary commentators. The problem is that in general the attacker doesn't actually need the victim's hidden authenticator. All they need is an authenticator that will work and I'll give them that authenticator if they ask me for one by requesting the form themselves. What I need is a way to tell apart the attacker's authenticator from the victim's authenticator and I don't have that in general.
(You might think that I could embed some version of the request's IP address into the authenticator. Unfortunately I've already discovered that that doesn't work these days; people's activity can legitimately hop between IP addresses too much. In theory I could try to fingerprint the specific browser from various identifying information it sends, but I don't feel like going there and it's a heuristic.)
This is what browser cookies do in the standard CSRF approach. CSRF cookies let us identify browser sessions so we can tell that the attacker's 'authenticator' doesn't come from the victim's browser session. And cookies attach to the browser session in a way that is deliberately invisible to the attacker. Once you have that session identification you can junk anything else in the authenticator because all you really need to do is tie the request to a particular browser session and reject cross-session requests.
(Realizing this has changed my thinking about CSRF cookie lifetimes. Initially I thought that they should be cleared after a successful form submission for somewhat fuzzy reasons; now I think that you're better off having them persist.)
Sidebar: when I think signed authenticators do work
When they work is if you actually have user logins, because then an attacker A can't manufacture a valid authenticator for user B. They can manufacture an authenticator for themselves (as before you'll give them one), but you'll detect that the authenticator's user is not correct when the attacker has the victim submit the form.
(This is why I could protect myself and a few other people who actually have logins here, but not most people who don't. One non-login authenticator can't be told from another non-login one.)