17

The Spring docs state:

Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

I'm interested in why? Why is it OK to disable CSRF protection when building a service whose only clients are non-browsers, but it should be enabled when the service talks to browser clients?

user3840170
  • 172
  • 7
hotmeatballsoup
  • 307
  • 2
  • 7

2 Answers2

24

It comes down to the fact that CSRF is an attack against browsers, so if your service is exclusively used by non-browsers there's no point in using anti-CSRF defences, which can be expensive so may be worth disabling.

When a browser interacts with a server, each request comes in separately, so if the service wants to have authentication it needs to add in some scheme to connect requests (to avoid having to have the user authenticate every request). One common way is to set a cookie to the user's browser, which is automatically send when every subsequent request by the browser).

  1. Client logs into service
  2. Server sets a http-only cookie
  3. Malicious script in browser sends a request to e.g. transfer money to the attacker (browser automatically attaches cookie)
  4. User loses money

vs. with protection

  1. Client logs into service
  2. Server sets a http-only cookie
  3. Malicious script in browser sends a request to e.g. transfer money to the attacker (browser automatically attaches cookie)
  4. Server rejects the request as the it doesn't have the correct CSRF fields.

However malicious scripts can make requests to the server, and the browser will helpfully included the cookie. However the script won't have access to the cookie directly (assuming the right cookie option is specified). Therefore a protection against CSRF is to have something in the request separate from the cookie (i.e. a hidden field on a form) that can be verify the request came from a proper form, rather than a script.

CSRF relies on the browser sending the cookie with a cross-site request automatically, since Javascript/attacker's site don't have access to the cookie.

CSRF protection relies on the server correlating something the browser sends automatically (the cookie) with something in the form (the token).

A non-browser client will be in control of both the token and the cookie so can make them match (if it can get the cookie at all). So there's no point having complicated CSRF protection if the service is never going to be accessed by a browser.

TL/DR - CSRF is inherently a browser attack, so protections against it are only required for services that might be accessed by a browser.

Douglas Leeder
  • 1,939
  • 14
  • 9
  • Awesome answer @Douglas (and +1!) and it _mostly_ makes sense, but I'm a little fuzzy on what you mean when you say "_CSRF protection relies on the server correlating something the browser sends automatically (the cookie) with something in the form (the token)_". Any chance you could give me a specific (but simplified) example of a CSRF browser attack when CSRF protection is **and isn't** enabled? Seeing the comparison between the two (protection enabled/disabled) will probably fill in all the missing pieces for me. Thanks again so much! – hotmeatballsoup May 18 '21 at 14:21
  • 13
    Note however that a form (or HTTP POST endpoint) which is *designed* for a non-browser client may still be *accessible* to a browser client. Your threat model should concern itself with whether a browser can be fooled into submitting a (valid) cross-site request, not with whether or not you intended for browsers to submit any requests at all. – Kevin May 18 '21 at 21:59
  • 1
    One example, your website depends on cookies to maintain login session. User logs in to your website. An attacker injecting some javascript (via comments, some library you use, hacking your webserver etc.) can now make requests for the user's personal information because the browser will automatically attach the cookie to any request to your URL (so all requests, even those not made by you or your user, are logged in). This is CSRF. Obviously this only happens because the code is running in a browser.. – slebetman May 19 '21 at 07:03
  • 1
    .. If your API is accessed via an app or a hardware device then there is no UI for the user to login to your site and usually (with the exception of you displaying your page in a Webview - which is after all an embedded browser) there is no javascript engine to execute 3rd party scripts. So unless it's a browser CSRF is not useful – slebetman May 19 '21 at 07:05
  • It's actually kind of wrong. Just because it's meant to be called by something else doesn't mean a CSRF attack doesn't exist (stealing login from some other web app on the server to log into this endpoint). – Joshua May 19 '21 at 17:05
  • @Kevin if it's not used by legitimate users through a browser, then noone's browser ever has a stored cookie that might be stolen/reused with a CSRF attack. If a browser is fooled into making a cross-site request, it would be identical to whatever an attacker could make directly; you could steal an user's browser session if one existed, but the point is that such sessions don't exist in this case. – Peteris May 19 '21 at 22:16
  • @Peteris: If it's on the same domain as something else (which is targeted at browsers), then cookies will be reused. Those cookies might or might not give rise to CSRF attacks. I did not say that a CSRF attack necessarily exists, only that the form or endpoint should be *evaluated* to determine whether or not an attack exists. – Kevin May 19 '21 at 22:18
5

Because the threat model is different.

In a browser context, we have an expectation that the browser user should be able to navigate to arbitrary web pages without worrying about it making unauthorised actions on the user’s behalf. This is despite the fact that webpages may initiate fetch requests to arbitrary external resources, using the user’s pre-existing authorisation token (i.e. cookies), and have certain limited control over the parameters of such requests, though they generally are not able to see the contents of the response. CSRF protection is meant to guard against this kind of threat, where the attacker may initiate more-or-less arbitrary requests on someone’s behalf, but cannot generally see the responses.

In an analogous situation outside the browser, the threat model is different. Native applications can open arbitrary socket connections to arbitrary hosts, have total control over initiated requests, and can always see the full response from the server. The answer to the analogous problem of ‘what if I run an application that may initiate unauthorised requests on my behalf?’ becomes the punchline of the well-known doctor joke (‘well, don’t do that’). As Raymond Chen likes to put it, you are already on the other side of the airtight hatchway. Any CSRF protection scheme can be trivially bypassed by a native application; it would only amount to security theatre.

That said, pay attention to how the advice about CSRF protection you quoted is worded: it only suggests you may want to disable it if your endpoint can never be used in a browser context. As long as a web browser can initiate authorised requests to it at all (whether you intended it for such use or not), CSRF protection may offer some value, even if native applications can bypass it easily.

user3840170
  • 172
  • 7
  • What prevents an attacker to prepare a html page with a form which sends a malicious request, since many apis use basic auth the victim might just enter his credentials – wutzebaer May 20 '21 at 08:53