0

I have the Angular application where CSRF protection is implemented using Cookie-to-header token. It is default AngularJS mechanism to counter CSRF, which uses cookie XSRF-TOKEN and header X-XSRF-TOKEN. Only JavaScript that runs on my domain can read token from cookie and send it inside header, so it is the header that provides the protection. So it looks like stateless CSRF protection, where server does not safe and verify token correctness.

But someone reported as a vulnerability that server does not verify token correctness and it is possible to send arbitrary value in cookie XSRF-TOKEN and header X-XSRF-TOKEN and as long as both values are the same server accepts the request.

enter image description here

Is it really a vulnerability? At the first time reading this I thought that it is mistake and that is the way how this mechanism works, but in Angular documentation (https://angular.io/guide/http#security-xsrf-protection) I found this:

To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the X-XSRF-TOKEN HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication cookie with a salt for added security.

Does this mean that server should remember token value for every user and verify this value and do not accept requests like on the screen above?

2

The issue your vuln reporter is highlighting is the standard weakness of cookie-based CSRF protection. There are ways to plant cookies on a site - in particular, if the site doesn't use HTTP Strict Transport Security, a local network attacker (or anybody else with a man-in-the-middle position) can usually plant a cookie via HTTP that will also be sent in HTTPS (what happens when HTTP-set and HTTPS-set cookies are both set with the same name depends on the browser and sometimes also on the server, but an attacker can usually adjust for that).

However, this isn't actually vulnerable, even to the extent that double-submit cookies are generally a vulnerable method of CSRF prevention. The reason actually has nothing to do with either the cookie or the value. Instead, it's quite simple: a cross-site request from a browser simply can't set any custom header unless you deliberately configure CORS to allow this. If you haven't configured CORS to allow setting that header, then the actual value of the header can be random, constant, or even empty - and doesn't need to be validated beyond ensuring that the header is present at all - and you'll be safe from CSRF.

Note also that it's entirely possible to make CSRF protection stateless without introducing any (new) cookies. Have the server provide the client (either in page content or in an API response) with an HMAC of the session token (whether it be a random token, a JWT, or something else) using a key that is the same across the server cluster but not exposed to the clients. Use that HMAC as your anti-CSRF token, passed in whatever method you want (other than cookies or other automatically-sent content, of course; I recommend a header for the reason above but POST bodies work fine too). Validating an HMAC is extremely fast, the key is the only server-side data required and is both short and constant, it's guaranteed to be unique not only to every user but to every session of that user (at least, as unique as your session tokens themselves are, which is hopefully the case), and it doesn't expose any meaningful data about the session token even if an attacker learns the CSRF token value somehow.

1

No, this is not a CSRF vulnerability. Cross-site request forgery works by exploiting the fact that, by default, browsers include any previously set authentication cookies in cross-site, non-CORS requests. If such a request is sent from a client that is not the user's browser, it will not include those authentication cookies and will therefore not allow the attacker to control any non-public functions of your applications (unless you have some other vulnerability).

If an attacker does try to send this request via the user's browser, it will still not work, as third party sites cannot control the contents of the Cookies header in cross site requests (unless you also send Access-Control-Allow-Headers: * or Access-Control-Allow-Headers: Cookie in your response, I suppose).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.