6 ms·
It seems to me the suggestion to require the 'X-Requested-With:XMLHttpRequest' header to be set is the best way to handle this, much better than some JS tweaki
by coderrr 16y ago
It seems to me the suggestion to require the 'X-Requested-With:XMLHttpRequest' header to be set is the best way to handle this, much better than some JS tweaking. It doesn't make any assumptions about javascript syntax or implementations. And the only way I can think to get around it is some http request splitting exploit via a proxy.
If you only return data to XHRs then you're protected by same origin policy and all <script> tags will get no data.
-EDIT-
When I first read "a better option is to require custom XMLHttpRequest headers" I thought this is what they were talking about. After a second look they probly mean setting a custom header yourself using the XHR object. This would work too but now I'm wondering if there's some way around my solution. Because why would they advocate a custom header if checking the X-Request-With header alone is enough?
- EDIT -
Was just in the shower and remembered why they probly don't advise to just check the X-Requested-With header. There are ways for an attacker to get around the XHR same origin policy with dns pinning/rebinding attacks. If you required a custom header with a session cookie which the attacker didn't have access to this would mitigate that kind of attack. EDIT: Nevermind, as long as you're checking the Host header a dns rebinding attack wouldn't matter.
- jashkenas 16y agoThis sounds like an even better fix -- nicely done.
- mrkurt 16y agoYou could just use the Origin header from CORS: http://www.w3.org/TR/cors/#origin-request-header http://www.w3.org/TR/cors/#origin-request-header
- coderrr 16y agoBut how many browsers actually send the Origin header currently? I just checked Firefox and Chrome and neither sent it on a <script> or XHR request.
- nbpoole 16y agoIt definitely isn't set via <script>. I know it's sent when you make an XHR request via jQuery, so I assume you can set it as a custom header if you're rolling your own XHR.
- coderrr 16y agoAh sorry, I was only checking same domain XHRs, which doesn't seem to send the Origin header. That combined with the fact that Origin isn't sent for <script> tags seems like it can't be used to prevent CSRFs.
- nbpoole 16y agoIt might not send it automatically (I don't know, I haven't tested it), but since you're the one building the XHR, you can send the header if you want. The same origin policy won't let you see the results of a cross-domain request, so it seems like requiring the header is an effective technique. Obviously this is only true for read operations: anything that updates state would still be vulnerable to CSRF (since you don't need to be able to read the result to make the request).
- coderrr 16y agoI'm pretty sure you can't set the Origin header yourself. That would kindof defeat the purpose of it. If anything they'd only allow you to specify whether or not to include the header. But I doubt any browser even lets you do that: $.ajax({url:'http:// http:// asdf.com/1,beforeSend:function(xhr,set){xhr.setRequestHeader('Origin', 'http:// http:// realorigin.com)}}) Refused to set unsafe header "Origin" So since you can't force an Origin header to be on all of your legit API requests, you won't be able to differentiate them (using the Origin header) from an attacker with a <script> tag.
- nbpoole 16y agoI'm not seeing the same behavior you're seeing. Try using $.get instead of $.ajax? Edit: I was confusing X-Requested-With and Origin. My apologies.
- tosh 16y agogood point, I was confused by the 'custom' recommendation too.
- nbpoole 16y agoYou're absolutely correct. Origin or X-Requested-With (or any other custom header) are a good source of protection for cases like this.