1

Considering the following facts, using CSRF token for a restful API (which of course is intrisincly session-less) seems inevitable:

  • storing JWT in local storage(any where other than http-only cookie) makes the API vulnerable to XSS attack.
  • storing jwt in http-only cookie makes the API vulnerable to CSRF attack

So in order to make the API secure against, both XSS and CSRF attacks, CSRF token must be implemented in the system. My question is how?

  1. Should I define a route like /api/csrf so that the client is forced to send a request (containing their http-only cookie, which holds their JWT) to that endpoint, before each POST/PATCH request, to get a CSRF token and attach the token to the aforementioned POST/PATCH requests?
  2. Considering that there are no sessions, In server-side, Should I store the mapping to CSRF and user id(JWT) in database/redis?

Are the abovementioned solutions valid and secure? Are there any standard way to deal with this problem?

Gandalf
  • 113
  • 4
  • Do you need your API to be accessible from the browser? If not, you can simply disallow cookie-based authentication and force the user to always specify a token in the `Authorization` header, at which point neither attack should be a problem. – bk2204 Dec 20 '21 at 01:21
  • Yes, it should be accessible from browser, and the frontend is an SPA. – Gandalf Dec 20 '21 at 06:04

1 Answers1

1

You shouldn't worry about your API - that is being accessed via web UI from a browser - being exploitable via XSS attacks, because it is inevitable.

If you have an XSS vulnerability, that can be used to bypass any CSRF protection, because the attacker can execute script on the trusted origin as the user.

In your example 1., XSS could be used to call /api/csrf with the users (httponly) cookie, the CSRF token can then be read out from the response, and the POST/PATCH request issued (the same way the actual app that used the API would do).

The important thing is that your API does have CSRF protection. How it is implemented doesn't really matter. CSRF tokens in a POST parameter or header would work fine and are the recommended approach; you could also send the API auth token in a custom header; and even a simple custom header such as API: 1 would work as CSRF protection in most cases, as custom headers can't be sent cross origin (though I'd recommend one of the former approaches because it is more robust).

tim
  • 29,122
  • 7
  • 96
  • 120