Wednesday, March 19th, 2008
A colleague and I were tossing around the idea of preventing XSS Exploitation with CSRF tokens. Now, before people start going “high and right” on me…hear me out… I DID NOT say “prevent XSS” with CSRF tokens, I said prevent “XSS Exploitation” with CSRF tokens. This discussion arose after someone presented me with the following scenario (this same scenario has been presented to me many, many times… typically at a bar after a few drinks):
You come into an organization and take over the application security department because the old security person left/was fired/was arrested/whatever. You take a look at the 10 million line flagship application and realize that its riddled with XSS holes, yet you don’t have the resources/time/cojo’s to fix all the exposures. What do you do?
This scenario is usually followed up by a pitch to sell me on some Web Application Firewall product….. I’ll put my thoughts on WAFs aside for a second… and I’ll try to get to the underlying issue of the scenario presented above: You need to do something to stop your customers from getting XSSd, you don’t have much time, you don’t have many resources and there is a ton of code to go through.
Now, what if you required CSRF tokens/canaries for every request? This doesn’t “fix” the XSS exposures, but it makes it a LOT more difficult to exploit (unless you want to exploit yourself). The CSRF tokens effectively prevent an attacker from sending the XSS to anyone else. Considering many token/canary values are implemented at the framework level, in most cases it would require a configuration change for the application. Now, once every page is protected by the canary, you can systematically examine the “high priority” pages or pages where canaries don’t make sense and remove the canary requirement after that particular page/functionality has gone through a review. In order to prevent the attacker from sending their own canary value, the CSRF token would have to be tied to the current users session (most good implementations do this anyway).
Now, once again, this DOES NOT FIX XSS, it just makes exploitation harder. This isn’t a new concept, in fact this same type of approach is being used by modern day operating systems. Take buffer overflows for example, protections like DEP, ASLR, Stackguard, GS flag… these protections do not prevent developers from writing buffer overflows and they do not “fix” buffer overflows… they do make exploiting buffer overflows a lot more difficult (unless you’re a Litchfield brother, HD Moore, or Alexander Sotirov).
Now, of course there are some cons to this strategy… First, the XSS exposures are not fixed (the WAFs don’t fix them either). This doesn’t protect against persistent XSS. There will be some performance hits to your web server when you have canaries for each request. This will NOT help you defend against injection attacks like SQL Injection or Command injection, that will require an audit… on the flip side… if you’re relying solely on a WAF to protect you against SQLi and Command Injection, I’d be worried…