2

I am developing an ASP.NET Core web api project whose only client will be a mobile app developed in Xamarin. There will be no web frontend for the application.

Can CSRF attacks be executed if the user can only login and consume the api from the mobile app?

EDIT

The api performs authentication by username and password by calling an endpoint configured with allow anonymous access. If the authentication process is successful, it returns a JWT that is used to authorize future calls.

CristisS
  • 123
  • 5

2 Answers2

4

A CSRF attack can only be done with requests with those three http request content types: application/x-www-form-urlencoded, multipart/form-data and text/plain. If your end point checks the request content type and makes sure it is not one of those three, that end point is protected from CSRF. So if you make the request content type be something like application/json, and you check that in the code (not just parse http request body using a json parser but actually verify the http request content type header), then you're safe. For existing deployed APIs with clients you do not control, maybe you won't be able to do this.

Another good protection, if you need to allow cookie authentication, use SameSite: Strict cookies if you don't need to allow cross origin requests.

If the end point you wish to protect doesn't do anything without authentication and only accepts authentication using a token, not a cookie and not http basic auth, then a browser doing an AJAX request from code on a malicious site won't be able to perform an authenticated request, and that is also a complete defense against CSRF. This seems to be your case.

Z.T.
  • 7,768
  • 1
  • 20
  • 35
  • The first two proposals (SameSite and changing content type) don't apply to apps and won't help secure it. Your Java code is talking to the API and submitting requests, not a browser. SameSite will not do anything (the same-origin concept doesn't exist in an app because, well, it's an app and not a website running in a browser on a domain) and your code is not going to deny you to use certain content types. And if it did, your app would be broken rather than secure. The last paragraph would be a secure solution, though! – Luc Apr 09 '21 at 11:07
  • CSRF as a concept only exists in the context of a browser and a malicious site causing the victim's browser to perform HTTP request to the site. All HTTP server security has to contend with the fact that anyone can send anything at all toward the sever, but they don't have a cookie that they can cause the browser to send. – Z.T. Apr 09 '21 at 11:11
  • Exactly, so setting `SameSite: Strict` or using `application/json` won't prevent an attacker from sending the HTTP request, as you suggest doing in this answer. – Luc Apr 09 '21 at 11:21
  • Of course it will protect the user. Imagine a bank has an endpoint to transfer money from logged-in user's account to a target account. The victim is logged in to this bank. They navigate to a malicious site that uses JS code to create a form to transfer money and causes the browser to submit it. If the login cookie is SameSite: Strict, then the request will be sent without the cookie, so it will arrive and be unauthenticated and the bank will not do anything. If the request has to be sent as json and the server checks that, the malicious site can't get browser to send that. Both defeat CSRF. – Z.T. Apr 09 '21 at 11:26
  • If the attacker doesn't have the ability to use the victim's cookie that they have in their browser, there is no attack at all. Of course the attacker can use curl to send any request. But how are they getting the victim's cookie to steal their money? – Z.T. Apr 09 '21 at 11:27
  • "*... that uses JS code to create a form*" This is an app, not a website. I can't make *your* app run *my* javascript code (unless you explicitly, on purpose, expose some way for me to do that). You're confusing two concepts here: website and app. If you have an API that is used by *both* a website and an app, then it needs protection because an attacker can make use of web attacks. But OP is asking "Can CSRF attacks be executed if the user can **only** login and consume the api **from the mobile app**?" (emphasis mine) – Luc Apr 09 '21 at 11:29
  • "*If the attacker doesn't have the ability to use the victim's cookie that they have in their browser, there is no attack at all.*" Once again, *exactly*. That's my point :D. OP is asking whether there is an attack from a mobile app possible here, and the answer is basically "no". – Luc Apr 09 '21 at 11:31
  • I don't consider whether the attack is "from a mobile app" or not. I consider what the API endpoint does on the server. If the API requires auth and only accepts a form of auth that a browser submitting a form can't send, then the API is protected from CSRF. – Z.T. Apr 09 '21 at 11:33
  • Exactly, so that last paragraph makes perfect sense for both apps and websites. But the first two apply only to websites and won't do anything for apps, which is what OP was asking about. FYI I've also added some detail to my answer just now. – Luc Apr 09 '21 at 11:39
  • Eh, ok, but security vulnerabilities are introduced by later changes. Suddenly there is a way to get a cookie for the same domain or whatever. An answer that tells you how to protect your server from CSRF regardless of the type of client you intend you use is more useful. – Z.T. Apr 09 '21 at 11:41
  • Okay, so why not suggest only what is effective in both scenarios (the last paragraph) rather than have people first read through other stuff (that they don't know won't help them) to get to that solution? – Luc Apr 09 '21 at 12:13
  • Why won't it help them? For example, if the server endpoint requires json content type on the request, that's a protection from CSRF regardless of what type of client you use or how your auth works. If they implement that, it's good. – Z.T. Apr 09 '21 at 12:15
3

A CSRF attack works by making the browser submit a request to another website. Because the browser automatically adds cookies to outgoing requests, the website will see that you have a valid session (assuming you're logged in at the time) and process the request, even if it came from evil.example.com. To protect from this, you verify the referrer, or add and verify some token that is not a cookie (commonly called an anti-CSRF token).

By understanding the attack and being an app developer (knowing how apps work), you might already see that CSRF attacks do not apply to apps in the same way.

If you have broadcast events that trigger an action in your app, then of course you should check with the user if they really want to do that, because any other app can trigger it (unless you require a custom permission to trigger the broadcast receiver). It's different from websites because it's intentional: you need to explicitly put in your manifest that "yes, I want others to be able to call this function". On websites, even the "delete user" feature in the admin panel is always exposed, you can't mark that as not being callable externally (anyone can browse to that URL), so to protect a website you need SameSite/anti-CSRF/referrer-checking.

In Android, you can open socket connections and do whatever. It's a proper programming language, not a browser. There is no concept of "same origin", "forbidden content types" or "forbidden headers" because you are the HTTP client, you're not asking the browser to send an HTTP request. And so it doesn't help to set things like SameSite or do referrer checking. But also, your code won't automatically add a security token to outgoing requests triggered by other apps. The only way would be if you explicitly add a broadcast event listener that lets other trigger actions in your app, but even then, the attacker can't specify the HTTP request, they can only trigger your listener to run.

An attacker can't simply (by default) make your app perform a malicious request. Anti-CSRF tokens or referer checking is not needed. You just need regular user authentication. Because the user is logged in on your app and not on the website, the attacker can't target the app's API from an unrelated webpage. An attacker can't make use of the session token (e.g. JWT) that your app obtained for the logged-in user, because the attacker can't specify a request for your app to add a session token to (unless you program it that way manually).

Luc
  • 31,973
  • 8
  • 71
  • 135
  • re: "_can't simply make your app perform a malicious request_", what if an attacker targeted the app's API from a non-related webpage? If webviews aren't completely sandboxed from each other, and the app uses a webview, could the attack work? – dandavis May 15 '20 at 18:32
  • @dandavis If I'm not mistaken, webview stores things like cookies in the app's folder, so e.g. `/data/data/org.example.app/...` so another app wouldn't simply be able to spawn a webview and get at your secret tokens. But that might be worth double-checking, even if I feel reasonably sure about this. As for talking to the API directly or from a non-webpage, then the authentication would be missing. – Luc May 15 '20 at 18:43