Tuesday, November 21. 2006
Today I was looking at rsnake's blog where he described how visiting two URLs in a row bypassed a CSRF protection implemented by last.fm. While it is funny that someone believes enforcing some kind of application flow control by URL checks can stop CSRF it was not what caught my attention.
It was one of the comments to that post that annoyed me. People like my special "friend" have claimed in the past that with an XSS on the site all CSRF protections are doomed. This is however not true.
The problem with XSS and simple CSRF protections is that at the moment there is an XSS on a site, the attack becomes a local one and is no longer a Cross Site Request Forgery. Because JavaScript comes with neat things like XMLHttpRequest or FlashRequest it becomes possible to read tokens embedded in local HTML forms and even fake HTTP headers. Therefore XSS can be used as a simple browser remote control.
However XSS attacks are limited (if there is no browser bug) to the current domain, therefore the answer to XSS attacks against CSRF protections is very simple: Keep XSS away from the HTML form's domain. For the application design this means: embedd all HTML forms in IFRAMEs that use a different source domain.
Example:
<iframe src="http://session_id.formular_id.example.com/">
While this makes application design trickier it keeps XSS from remote controlling your browser. If you embedd a formular id into the domain you can even have XSS in one of your formulars and XSS can still not control the other forms.
Update: the iframe URL was a bit unclear.... the formular_id is NOT the formular token. That is still embedded in the FORM. The id is simply an id that is different for all forms. Same for the session_id. It is not necessary the session_id of the user but an "encoded or encrypted" variant that allows having different domain names for different sessions.