1

I have an API endpoint that is accessible by both native (console, mobile apps) and Javascript based clients.

How do I ensure that the CSRF AntiForgeryToken is only invoked during Javascript calls?

  1. Can this be done in a non-authenticated/anonymous manner?

  2. Or are the entitlements listed within an authentication token the only way for a server to determine if CSRF should be applied? (native vs browser flow)

  3. Do Javascript clients (not the libraries themselves) have a specific set of HTTP headers and corresponding values that I can rely upon to determine the request type?

  4. Does separating the API services (APIController) onto a separate web server, with a different DNS name, allow me to use Same Origin Policy (SOP), to effectively force the Javascript clients to apply the headers that would otherwise be omitted in scenario 3 above?

makerofthings7
  • 50,090
  • 54
  • 250
  • 536

1 Answers1

2

You have a few options, in random order:

1. Different authentication schemes

Web browsers frequently authenticate by session identifiers in cookies. Many native apps attach auth tokens directly in the request header (in an Authorization header or some other custom header key). CSRF is generally only a concern when authentication comes up with cookies. As a result, if your application only checks CSRF tokens when the user is authenticated via cookies, and if your native apps don't use cookies for identifying themselves, then you'll be fine.

2. Client side certificates

This probably isn't worth the trouble, but if you enable client identification via client-side certificates (and do it properly) then you can be certain that the person on the other end of the conversation is an app, not browser, and disable CSRF validation.

3. Custom headers

One potential strategy would be to include a custom header with the request from the native app, and disable CSRF protection if present. This is likely a safe strategy. Further reading here:

CSRF protection with custom headers (and without validating token)

4. Anonymous requests

You asked about doing this is an anonymous manner. To some extent (aka this is not 100% applicable) anonymous requests don't need CSRF protection because the whole point of a CSRF attack is to take over a user's session. If a user is anonymous and not logged in, then there probably isn't much to take over anyway. An application without logins, which stores no state as a result of client actions, doesn't really need CSRF protection in the first place (although I may have misunderstood what you meant there).

5. Separate Endpoints

I think this is what it really comes down to. If you have an endpoint serving two different clients in two different ways, then I think the issue is that you need two endpoints, one with CSRF checks disabled and one with them enabled. Of course this only actually works if the two endpoints are authenticated differently, which really just brings us back to item #1. If you have two separate endpoints, one for native (with CSRF disabled) and one for web (with CSRF enabled), but both accept the same cookie for authentication, then an attacker can perform CSRF attacks the second they realize that that native API exists and accepts the same cookie as the web.

Ideally I think you should have two separate endpoints. Even if the two perform almost exactly the same action, you can always just structure your system so that you use the same basic code to fulfill both API calls, but they have separate endpoints and separate authentication logic. Of course the other option would be to have one endpoint meant for both systems, that operates exactly the same for both. Having one endpoint that tries to operate differently for two different systems is probably the easiest way to get yourself in trouble.

I didn't hit up your questions point-by-point, but I believe these are effectively all the options you have, so hopefully it answers your question anyway.

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
  • Would same origin policy (as enforced by Javascript) be a sufficient barrier against CSRF attacks, because that would force all js clients to place a HTTP header that can't be altered by js code? The api endpoint could then use this header to determine if the call is coming from a native client vs a js client? – makerofthings7 Feb 07 '19 at 20:18
  • And then allow the situation where if a native client adds the cross origin headers that result in antforgery tokens to be validated, then allow that complexity for those developers who want to do things the hard way? – makerofthings7 Feb 07 '19 at 20:20
  • @random65537 Getting the SOP and CORS involved sounds more complicated, and prone to error because you're basically trying to use it to solve a problem that it wasn't designed to solve. That sort of thing tends to make more problems in the long run than it solves. I think that requiring a custom header will effectively provide the same protection anyway, and then you can easily and clearly enforce that server-side. Less shenanigans. – Conor Mancone Feb 07 '19 at 22:00
  • So if I set a custom header that can only be read/written to by native clients, and not javascript, then I can ensure that CSRF processing only occurs under the correct caller. Do you have any suggestions on what the value of that header should (or shouldn't) be? (e.g. `access-control-allowed-headers`, but without CORS as you suggest) – makerofthings7 Feb 07 '19 at 22:39
  • 1
    @random65537 The client sets the header and the server verifies its presence I linked to a relevant question. The first answer has some cautions to keep in mind, but there aren't any known attacks at the time – Conor Mancone Feb 07 '19 at 22:44
  • Got it. I'm clear on my approach, thank you very much. – makerofthings7 Feb 07 '19 at 22:46