How does ValidateAntiForgeryToken fit with Web APIs that can be accessed via web or native app?

bdukes picture bdukes · Apr 2, 2013 · Viewed 8.8k times · Source

I'm trying to understand how I will be able to craft an API using ASP.NET Web API which will be protected from CSRF, while still being accessible from non-web environments (e.g. native mobile applications).

My first thought would be that a non-web environment can never successfully pass an anti-forgery token validation, since it doesn't have a form that is posted. Is this true? Is there any way to make validation work?

If there isn't a way to validate, my second thought is to offer an API which validates anti-forgery tokens for web calls but not for non-web calls. However, it seems like an attacker would just as easily be able to use this "non-web" API for a CRSF attack, right?

Is the answer that the non-web API needs to only support a non-web authentication mechanism (OAuth?), so that requests to it cannot be replayed via a browser? Or is there a simpler way?

If that's the only way, is there an easy way to turn off all of the insecure authentication mechanisms? Shouldn't there be a somewhat simple/happy path in ASP.NET Web API to support these scenarios?

Answer

blowdart picture blowdart · Apr 10, 2013

CSRF only becomes a problem when you are using a persistent auth mechanism such as cookies, basic auth, NTLM etc. Mike Wasson has an example of using CSRF against webapi in Javascript - and I've seen versions in DelegatingHandlers ....

As CSRF is only a problem in web scenarios you can argue there's no real need to check for non-web requests. Every ajax request from a browser, whether via jquery, the native XmlHttpRequest classes or whatever comes with a header - X-Requested-With, which will have a value of XMLHttpRequest. So you could limit your CSRF checks to just requests with that header, as anything without it must have come from outside a browser.

Having said that if you are authenticating, I'd look at some sort of shared secret or OAuth mechanism, and have a DelegatingHandler server side to validate, and in the web app just put the token somewhere that it can be picked up via javascript and sent via an X-Authentication header - as it's not persistent and needs to be attached to every request (just like the CSRF token) there's no CSRF problems. Dominick, as ever, documents this sort of thing well.