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.
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.
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.