(First read the story of how Nathan Wilcox showed us CSRF vulnerabilities in Tahoe, the Least-Authority Filesystem and won an "I Hacked Tahoe!" t-shirt: Nathan Wilcox and CSRF attacks.)
There is a general principle here which deserves to be more widely appreciated. A CSRF attack looks, under the hood, a lot like sharing. (The biggest difference is that the sharer is not actually the friend of the receiver.)
bad guy victim site
.------. information .-----. authority .-----.
| >:-} | ----------> | :-| | ========> | ... |
'------' '-----' '-----'
Figure 1 -- CSRF attack: the bad guy sends information (such as a form or a hyperlink or a page with Javascript on it) to the victim who sends a request -- an authority-wielding message -- to the site which has an effect. The victim already had the authority to do that thing, such as to delete their private files, but they didn't realize what the form or hyperlink was going to do when they clicked on it.
friend friend site
.------. information .-----. authority .-----.
| :-) | ----------> | :-) | ========> | ... |
'------' '-----' '-----'
Figure 2 -- sharing: a friend sends a message (containing something such as a form or a hyperlink or Javascript) to another friend which gives the other friend the ability to do something on the site when they click on it.
This insight leads us to propose the following aphorism: Solve CSRF attacks by making references unforgeable, not by making them unshareable.
Currently most people who face CSRF attacks assume that the following strategy is the only sensible one:
Most people think of CSRF vulnerabilities as being a failure to prevent sharing of access powerful things -- you accidentally made it so that someone else (the attacker) was able to give an HTML page, URL, or Javascript applet to a different user (the victim) which had a powerful effect. And so most people think of fixing CSRF vulnerabilities as making sure that powerful URLs are really, really unshareable, even when malicious attackers attempt to work-around your anti-sharing techniques. We think of CSRF vulnerabilities as being failures of unforgeability -- the attacker was able to generate a reference which would (in the hands of the victim) do something that the attacker himself was not authorized to do.
The strategy of making references to powerful resources unshareable can work, but it is complex, it inconveniences users, and it has an important limitation: it doesn't help you if you want to allow users to share certain powerful resources with one another. The "make references unshareable" strategy doesn't prevent you from making certain resources shareable, but you'll have to implement the sharing of those resources separately, not at the web layer (with URLs, HTML, Javascript), but instead as logic inside your web site. (And when you do, you'll have to be careful not to accidentally reintroduce a CSRF vulnerability.)
bad guy victim site
.------. information .-----. nothing .-----.
| >:-{ | ----------> | :-| | | ... |
'------' '-----' '-----'
friend friend site
.------. information .-----. nothing .-----.
| :-) | ----------> | :-( | | ... |
'------' '-----' '-----'
Figure 3 -- standard CSRF defense: the web site attempts to prevent CSRF attacks by making it so that the victim can't do anything by clicking on a form or a hyperlink, or executing some Javascript unless that form, hyperlink, or Javascript came directly to that user from the site, without going through any other user first. Obviously, this also prevents sharing (at the web layer).
One problem with this strategy is that the anti-sharing mechanism is an inconvenience to users. It almost always involves logging in with a user name and password, and for the safer variants it might involve logging in repeatedly due to precautions like session expiry. This strategy also completely excludes people who have not registered on your web site from being the recipients of sharing.
Another problem with this CSRF defense is that it prevents web sites from sharing powerful resources with one another, or user-generated content on the same site from sharing powerful resources with content generated by a different user. People have recognized this problem and are currently working on protocols to allow web sites to whitelist which other web-sites should be allowed to share access to which of their powerful resources. This whitelist approach is sure to suffer the same problems that all such whitelists have: it will occasionally let a bad guy share resources, thus enabling a CSRF attack, and it will often prevent good guys from sharing resources, thus preventing valuable new features.
The alternative CSRF defense that we propose is:
This completely solves CSRF attacks while also providing a natural, convenient method of sharing: just share the URL. This means that users can share resources with other users even when those other users have never created an account on your web site before. This is what we did in Tahoe v0.5.1.
bad guy victim site
.------. nothing .-----. nothing .-----.
| >:-{ | | :-| | | ... |
'------' '-----' '-----'
friend friend site
.------. authority .-----. authority .-----.
| :-) | ==========> | :-) | ========> | ... |
'------' '-----' '-----'
Figure 4 -- capability-oriented CSRF defense: every resource is controlled by an unforgeable reference. The bad guy doesn't have the authority to use the victim's resources, so he can't come up with a message that he could send to the victim which would use the victim's resources when the victim clicks on it. The friend does have the authority to use the resource that they want to share, and they can share that authority with their friend by sending their friend a copy of the reference. (If a message contains information sufficient to access a resource, then we label that message as "authority".)
One last note: the capability-based strategy of making all references unforgeable does not mean that all references have to be shareable. It offers a convenient way to implement sharing of resources, but it does not require you to allow that. For resources which you do not allow your users to share, the unforgeability of the references is solely a way to prevent CSRF attack.
Please let us know, by writing to the tahoe-dev mailing list, if you find this strategy to be helpful or if you find it to be problematic.