CSRF Token necessary when using Stateless(= Sessionless) Authentication?
Asked Answered
O

2

143

Is it necessary to use CSRF Protection when the application relies on stateless authentication (using something like HMAC)?

Example:

  • We've got a single page app (otherwise we have to append the token on each link: <a href="...?token=xyz">...</a>.

  • The user authenticates himself using POST /auth. On successful authentication the server will return some token.

  • The token will be stored via JavaScript in some variable inside the single page app.

  • This token will be used to access restricted URLs like /admin.

  • The token will always be transmitted inside HTTP Headers.

  • There's NO Http Session, and NO Cookies.

As far as I understand, there should(?!) be no possibility to use cross site attacks, because the browser won't store the token, and hence it cannot automatically send it to the server (that's what would happen when using Cookies/Session).

Am I missing something?

Opus answered 25/1, 2014 at 22:40 Comment(1)
Be careful about Basic Auth. Many browsers will automatically send the basic auth headers for the rest of the session. This can make basic auth as vulnerable to CSRF as cookie auth.Scaife
O
175

I found some information about CSRF + using no cookies for authentication:

  1. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
    "since you are not relying on cookies, you don't need to protect against cross site requests"

  2. http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/
    "If we go down the cookies way, you really need to do CSRF to avoid cross site requests. That is something we can forget when using JWT as you will see."
    (JWT = Json Web Token, a Token based authentication for stateless apps)

  3. http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services
    "The easiest way to do authentication without risking CSRF vulnerabilities is to simply avoid using cookies to identify the user"

  4. http://sitr.us/2011/08/26/cookies-are-bad-for-you.html
    "The biggest problem with CSRF is that cookies provide absolutely no defense against this type of attack. If you are using cookie authentication you must also employ additional measures to protect against CSRF. The most basic precaution that you can take is to make sure that your application never performs any side-effects in response to GET requests."

There are plenty more pages, which state that you don't need any CSRF protection, if you don't use cookies for authentication. Of course you can still use cookies for everything else, but avoid storing anything like session_id inside it.


If you need to remember the user, there are 2 options:

  1. localStorage: An in-browser key-value store. The stored data will be available even after the user closes the browser window. The data is not accessible by other websites, because every site gets its own storage.

  2. sessionStorage: Also an in browser data store. The difference is: The data gets deleted when the user closes the browser window. But it is still useful, if your webapp consists of multiple pages. So you can do the following:

  • User logs in, then you store the token in sessionStorage
  • User clicks a link, which loads a new page (= a real link, and no javascript content-replace)
  • You can still access the token from sessionStorage
  • To logout, you can either manually delete the token from sessionStorage or wait for the user to close the browser window, which will clear all stored data.

(for both have a look here: http://www.w3schools.com/html/html5_webstorage.asp )


Are there any official standards for token auth?

JWT (Json Web Token): I think it's still a draft, but it's already used by many people and the concept looks simple and secure. (IETF: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token-25 )
There are also libraries for lot's of framework available. Just google for it!

Opus answered 8/8, 2014 at 7:49 Comment(7)
Great summary on CSRF! I will note that storing your tokens in localStorage or sessionStorage is vulnerable to XSS attacks and that the data can be viewed by scripts on the page - so if you have a compromised script served from a CDN or if there is malicious code in one of your JS libraries, they can steal the token out of those storage places. See: stormpath.com/blog/… I think the most secure approach is to store a JWT + CSRF token in the cookie, and then place your computed JWT with the CSRF token inside it in the request header.Literature
Regarding: "The most basic precaution that you can take is to make sure that your application never performs any side-effects in response to GET requests." Is it possible for a CSRF attack to fake a POST request?Twig
Depending on the Server Side Application, it CAN be possible. There are Web Frameworks, that use something like http://.../someRestResource?method=POST. So it's basically a GET request, but the Server Application interprets it as a POST request, because it was configured to use the method parameter instead of the HTTP header. ... Regarding the common web browsers, they enforce the Same-Origin-Policy and will only execute GET requests to foreign servers. Though it could be possible to execute POST requests if the web browser doesn't apply those web standards (bug, malware).Opus
Addition to the Server Side App: It's still not possible to send a Request Body, because the common browsers will not allow this. However, if the Server App allows method=POST, it might also allow body={someJson} to override the default request body. That's really bad API design and extremely risky. Though if your Server App allows http://...?method=POST&body={someJson} you should really overthink what you did there and why and if it's necessary at all. (I'd say in 99,9999% of the cases it's not necessary). Additionally browsers can only send a few kilobytes this way.Opus
@BenjaminM notice that Same Origin Policy only prevents the javaScript code from accessing the result so while the request is "blocked" it actually reaches the server - jsbin.com/mewaxikuqo/edit?html,js,output I only tested this on firefox, but you can open dev tools and see that even tho you get "Cross-Origin Request Blocked" the remote server actually see the whole request. that is why you must have tokens or custom headers (and if possible both) to all your POST requestsEure
Great writing. So the answer the question is no, right?Coffin
Yes, basically the answer is "no", IF you're doing it right and follow the rules!. Read the comments and other answers here! You'll see that there are some pitfalls (like using session/localStorage or cookies, etc.). If you're not sure about this, you can combine CSRF with JWT, there's nothing wrong with it.Opus
R
68

TL;DR

A JWT, if used without Cookies, negates the need for a CSRF token - BUT! by storing JWT in session/localStorage, your expose your JWT and user's identity if your site has an XSS vulnerability (fairly common). It is better to add a csrfToken key to the JWT and store the JWT in a cookie with secure and http-only attributes set.

Read this article with a good description for more info https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

You can make this CSRF protection stateless by including a xsrfToken JWT claim:

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "[email protected]", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

So you will need to store the csrfToken in localStorage/sessionStorage as well as in the JWT itself (which is stored in a http-only and secure cookie). Then for csrf protection, verify that the csrf token in the JWT matches the submitted csrf-token header.

Race answered 11/5, 2016 at 17:32 Comment(9)
This seems like the most common-sense approach to security to me - especially if the javascript application is granted a refresh token. You really don't an attacker to csrf to be able to forge to token refresh method.Carolyn
Should one exempt csrf token usage during api authentication of user?Feller
It's worth pointing out (as others have also mentioned in comments on the source link) that any CSRF mitigation that uses a) cookies, which are not http-only or b) stores the CSRF token in local storage is vulnerable to XSS. This means that the presented approach may help keeping the JWT secret from an attacker using XSS, but an attacker would still be able to execute a malicious request on your API because he's able to provide a valid JWT (via the cookie, thank you browser) and CSRF token (read via injected JS from local storage/cookie).Community
Actually even a CSRF token cannot protect you at this level of XSS, since you are assuming the attacker can access localStorage, which the only way currently to access that is to have script level access, which they can take a look of the CSRF token anyway.Unguarded
Isn't that what @JohannesRudolph was saying? As soon as you store the CSRF Token in Web Storage/non-http-only cookie you are increasing your footprint of an XSS attack because those are accessible via JS.Mindexpanding
Thanks for your comments guys; I don't mean to give the impression this is somehow safe even if your site has an XSS vulnerability. You are all correct in that with the CSRF token saved in local storage that if there is an XSS vulnerability, an attacker would be able to forge requests. The difference is perhaps minor, but in the method I outlined, the JWT cannot be stolen (http-only secure cookie) compared with saving the JWT in local storage it can be stolen.Race
Not a total expert here, but if you're still exposed to XSS as you were in the beginning, I'm not sure the part It is better to add... really holds. Probably it is a little (?) more complicated for an attacker to get a hold of CSRF token, but at the end he's still able to perform a request on your behalf, even without actually knowing the JWT token. Is that correct? ThanksStopwatch
The JWT can't be stolen from the http-only cookie, but the CSRF token can be stolen since it's needed somewhere readable. If you have untrusted javascripts on your page you are still vulnerable, but I don't know if there's any real protection against untrusted js besides avoiding it carefully. If you're not using cookies then you're exposing the auth token, and if you are then you're exposing your CSRF token. Am I wrong?Daddylonglegs
Please explain how exposing the CSRF token to be stolen is any safer than exposing the JWT to be stolen, especially when the JWT is being automatically sent?Papery

© 2022 - 2024 — McMap. All rights reserved.