Security. Today, no application can survive the internet if it does not have proper security programmed into it - either by the framework used by the developer, or by the de
If you are using bearer authentication then CSRF is not possible by any attacker as they don't have the token value. It won't automatically be added by the browser to requests, therefore it is inherently secure against CSRF. See here for an explanation of CSRF and how a custom header can mitigate it. Bearer authentication solves the problem in the same way as the custom header cannot be added without CORS being enabled, or if CORS is active (which is common for an API), then as authentication against the API is achieved with the token value itself, any attacker will not know the value to provide (if they did they would simply use the value directly without CSRF), and the browser will not automatically supply the authentication in the same way it would for basic authentication, digest, etc, cookie authentication or certificate authentication.
For protection against XSS, which is a different issue, ensure all HTML output is HTML encoded (>
becomes >
). This could be done in the API itself if it outputs formatted HTML, or in JavaScript if it is up to the consumer to format output appropriately. There are functions built into JavaScript and frameworks like JQuery that can also help (e.g. textContent and text()).
From what I've read, I see that applications consuming RESTful APIs that use token-based authentication are vulnerable to XSS and not CSRF if the token is stored in localStorage/sessionStorage of the browser instead of in cookies. This is because, for CSRF to work, the application must use cookies. Am I correct?
More or less correct. An application that only uses a cookie for authentication and does not have any CSRF protection will be vulnerable to CSRF because cookies are automatically included in all requests.
But now that the tokens are stored in the localStorage/sessionStorage, the application becomes vulnerable to XSS attacks.
It's not that the application becomes vulnerable to XSS, it's that the authentication token becomes vulnerable to XSS. If your authentication token is sent as http-only
, then JavaScript (and thus XSS attacks) cannot read the value.
I think the article does a pretty good job of explaining how to use a session cookie and CSRF token. Let me try to summarize the article, as it's a little long:
http-only
cookie (and ideally also secure
— which the author did not mention — which prevents the browser from sending the cookie on an http request, only https requests) as the authentication token. In this way, the cookie cannot be read by JavaScript and thus cannot be stollen in an XSS attack.The article also goes into details about how to set cross domain headers if your static resources are on a different domain than your REST endpoints.
However, your approach is backwards to what the article said. You're putting the authentication token in localStorage and putting the CSRF token in a cookie. I would suggest flipping it back around, as the authentication token is more important than the CSRF token, and an http-only secure
cookie is harder for a bad guy to get at than localStorage.
The approach mentioned in the post above requires me to persist the
CSRFProtectionCookie
in a database of some sort. I do not want to do that. I do not want the database to be hit every time a authenticated request is made to the API.
You are thinking along a good path, here. What you're describing would be called a "stateless CSRF token".
Your approach to "Authenticated Requests" looks good. I'm not entirely sure you need to encrypt the CSRF token value, but it doesn't hurt.
this eliminates the need to persist anything to the database (or does it? Am I missing some loophole?)
You are correct, no loopholes.
But what is the overhead of decrypting and verifying hashes on every user request? Is it more overhead than database I/O?
I/O is usually much slower than a CPU bound calculation, even for something like encryption. That said, if you're really worried about it, you'd have to measure (which is easier said than done, of course).
Keep in mind that by storing the CSRF token in a JWT claim, the CSRF token will be valid for as long as the JWT token is. Even if you send the client a new JWT token, that old token and CSRF token will still be valid. This isn't such a problem for short lived tokens (say 10-60 minutes), but one of the benefits of storing a CSRF token on the server-side somewhere means that you can have one-time tokens for super sensitive operations. (Also, if you need to revoke a not-yet-expired JWT token, you'd need to store that state somewhere server-side, too. But now we're falling down a different rabbit hole...)
There's really no particular framework that's going to completely prevent XSS vulnerabilities simply because they can manifest in so many different ways. That said, your web app can use the Content-Security-Policy header to help prevent XSS attacks. The CSP header can be used to tell the browser which domains it's allowed to load resources from (such as JavaScript files). It can even be used to prevent in-line JavaScript from running (which is one of the major attack vectors for XSS).