5

I have a Single-Page Application, which is basically a consumer to my API which authenticates using the Authorization header. Now because I do server-side-rendering, I need to authenticate on the initial request, which means I need to use cookies to store the auth token.

Now as far as I understand, CSRF works like this in a typical website:

  • Find an endpoint that does something harmful like /delete-account which authenticates with cookies
  • In example.com, put a <img href="http://mywebsite.com/delete-account"> (or whatever for a POST request)

However, to me, it looks like that it is impossible for CSRF attacks to happen in the case of an SPA, even if authentication token is sent as a cookie. The normal procedure is a bit like:

  • User visits a page, say /account
  • Server renders page as per the authenticated user (given the auth cookie)
  • Web page is returned
  • Now if the user wants to delete their account, they could press the button, which would send a request to the API that authenticates requests only by Authorization header

Now in a CSRF attack:

  • <img href="/account">
  • Server renders and returns webpage
  • Umm, nothing happens?

I mean I can't think of a way I can be vulnerable to CSRF in this situation, even if I use cookies for authentication, and as far as I understand, CSRF attacks can't scrape data out of web pages, so returning sensitive data shouldn't matter, as long as it doesn't trigger an action.

So my question is, is it fine to not implement any sort of CSRF protection in this case? I'm so afraid of having a security issue regarding that.

OverCoder
  • 155
  • 1
  • 5
  • You should just use an AntiForgeryToken as it's an easy to implement countermeasure. – TGlatzer Jan 09 '18 at 22:40
  • @TGlatzer I do not use ASP.NET, but I see what you do mean. The thing is I don't want to implement something unnecessary, and I also have a public API, so making the API require a CSRF token is like.. kind of.. weird? A CSRF token is even irrelevant for a mobile app for example so API requiring a CSRF doesn't sound like the best idea. – OverCoder Jan 09 '18 at 22:52
  • Does your `Authorization` header value is different for each request? – hmrojas.p Jan 09 '18 at 22:56
  • An API with CookieAuth is - as far as I understood the topic - subject to CSRF. Either implement AntiCSRF-Tokens or use a token based authentication. – TGlatzer Jan 09 '18 at 22:56
  • @hmrojas.p No, but I could easily make it so given that I use JWT. – OverCoder Jan 09 '18 at 22:59
  • 1
    @TGlatzer If you read the first paragraph of the question body, I state that the API only authenticates with `Authorization` HTTP header. The only time a cookie is used for authentication is during the initial SPA render, which is a GET request that renders the initial web app frame and returns the application. – OverCoder Jan 09 '18 at 23:00
  • I probably misunderstood that. So Queries (as in non-state-changing operation for your application) are not subject to CSRF. BUT then you need to assure everything else can't use that cookie for authn. Also consider not securing the initial page and just send an generic "App is loading" – TGlatzer Jan 09 '18 at 23:08
  • @TGlatzer That would defeat the entire purpose of server-side rendering. – OverCoder Jan 09 '18 at 23:20
  • You can still render a partial page ... – TGlatzer Jan 09 '18 at 23:22

2 Answers2

4

Now if the user wants to delete their account, they could press the button, which would send a request to the API that authenticates requests only by Authorization header

Ultimately, it sends a request to perform an action which needs to be authenticated somehow. And, since you're using Authorization header for authentication, it somehow prevents CSRF unless you're using HTTP Basic Auth or NTLM. These authentication tokens are sent in each request similar to cookies.

I mean I can't think of a way I can be vulnerable to CSRF in this situation, even if I use cookies for authentication, and as far as I understand, CSRF attacks can't scrape data out of web pages, so returning sensitive data shouldn't matter, as long as it doesn't trigger an action

There are situations you might find yourself vulnerable to CSRF, here are few;

  1. What if your server accepts any of two i.e. either cookies or token?

-> I had recently encountered the same. The application would either need cookies or auth token. Since, cookies are always sent, you're assumed to be authenticated and your request gets processed leaving you vulnerable to CSRF again assuming your application allows sending Authorization token from any domain.

  1. What if your application leaks auth token which can be read cross-domain?

-> I have seen a number of apps fetching tokens from a predefined endpoint which somehow can be read crossdomain. Some possibilities are, JSONP, CORS, crossdomain.xml, JSON Hijacking, etc. This again leads to CSRF.

even if I use cookies for authentication

That is always vulnerable, you just need to play with final request which is an API request in your case.

So my question is, is it fine to not implement any sort of CSRF protection in this case? I'm so afraid of having a security issue regarding that

As a matter of fact, yes. Also, make sure you whitelist domains which can make request to your API and return Access-Control-Allow-Credentials: false. This, in my opinion, makes it fairly safe against CSRF- considering points mentioned above.

1lastBr3ath
  • 909
  • 6
  • 13
  • 1
    So basically, ignoring the possible *bugs* mentioned above, which do not exist (hopefully) in my case, and because I use JWT and not Basic Auth or anything, it seems OK then. One question though, how would I make use of `Access-Control-Allow-Credentials` in the case of a public API? It doesn't make sense, right? – OverCoder Jan 10 '18 at 12:33
  • 1
    If it's a public API, you could simply set **ACAO** to \* which implies **ACAC** to be false. It just makes sure that credentialed requests are not accepted. So, if a browser sends request along with cookies, it won't succeed. – 1lastBr3ath Jan 10 '18 at 18:39
2

Firstly, it's important to understand the following: you should implement something to authenticate a user and you should implement something to authenticate a request (Anti-CSRF). CSRF Attack use a session of a victim, so if your Authorization header value is the same for all session, your application could be vulnerable to a CSRF-attack, because your application validates only a user session, it needs to validates a request and this is possible using a token with the following features:

  • Long enough.
  • Pseudo-random.
  • Unique value.
  • One per-request.

Firstly, you should validate user session, if it's a valid user and her/his permissions or role, after that you should validate the request through the token, if it's a valid token then you can permit the request.

I hope this information helps you.

hmrojas.p
  • 1,049
  • 1
  • 8
  • 16
  • Well, `Authorization` isn't sent unless JavaScript says so, so using the `Authorization` header doesn't mean a CSRF vulnerability. I do understand what you mean by request origin verification, but where would I use that token? Would it be the same token I use for authentication? Would I be applying that token on only the SPA loading part, or on the entire API? Also if the token is one-time usage, what happens on the first-page visit? What also happens in multiple simultaneous sessions? Where would I store it even? – OverCoder Jan 09 '18 at 23:27
  • That token should be used on the view, as part of your parameters for a request and it should be validated on server, then it must be stored on scope request or view, so this token shouldn't be the same to authenticate user, it should be used to authenticate request, so you should a different mechanism to authenticate user, now this token should be used only for pages in an active session, so if your first-page is out of an active session, token isn't necceary. I share you a link with more information: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet – hmrojas.p Jan 10 '18 at 15:08