Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass CSRF token from server to client?

Tags:

security

csrf

This may sound like a dumb question. I wanted to be clear about this. How does csrf token help to identify the cross site request if token is sent to the client first and the client sends back the same token? Wouldn't the malicious client get the response from the server.

If we check the origin while sending the token, then doesn't the token checking thing seem redundant?

How can we be sure that server will only serve the token to the authorized client and what is the best practice to transfer the token from server to client?

I had asked a related question here but needed more insight into it. So asking a different question here.

Hoping for some answer with example.

Thank you in advance

like image 579
pramesh Avatar asked Jun 07 '18 02:06

pramesh


People also ask

How is CSRF token sent to client?

The client acquires a new CSRF token from the server by calling the REST endpoint baseURL/v1/csrf/tokens. The server generates a new, unique CSRF token and sends the token to the client in a custom HTTP response header. The header name is X-IBM-SPM-CSRF. The client retrieves the CSRF token from the custom header.

How do I pass CSRF token in REST API?

The client reads the payload from the cookie and passes it in the Authentication-Header to the server. The server validates the token based on the signature which is sent in the HttpOnly cookie. So, its CSRF-save and an attacker cannot steal the entire token via XSS because there is no JS-access to the signature.

Where do I put CSRF token?

Place the field containing the CSRF token as early as possible within the HTML file. Place the field that contains the token before any non-hidden fields and before any places where user-controllable data is embedded.


1 Answers

CSRF is basically about an attacker exploiting a user's existing session via the way cookies work in a browser. The underlying problem is that a cookie is sent with a request regardless of where (which origin, ie. domain) the request comes from, the only thing that counts is where it goes to. So if there is a user logged on to an application (having a session cookie), an attacker may try and get this user to visit his malicious website, from where the attacker can make requests to the application domain with the user's credentials (by fully POSTing the user to the application, or more subtly by creating ajax requests).

Note that this only applies if the authentication in the application is based on something that's sent automatically by the browser, most obviously a session cookie, but for example basic http authentication or client certificate authentication are also potentially vulnerable. Also CSRF only applies to requests that change something (state or data).

There is one important thing playing a role, the same origin policy (SOP) is browsers. A bit simplified, it means if something is downloaded from one domain (or more precisely: origin), then another domain will not have access.

So to protect against the attack described above and prevent an attacker on his own domain to have a user send unwanted requests to an application where the user is logged on, there may be several different strategies.

Synchronizer tokens

The application generates a csrf token, stores it in the user's session (server-side), and also sends it to the client by for example writing it in every form in a hidden field, or in one single field where Javascript can read it from and add to requests. This works, because an attacker on his domain cannot create a form or request with the valid token that's in the user's session, and also the attacker cannot read the token from an application page. Of course the attacker can try to download an application form to acquire a token, but then he would need credentials. The attacker needs both a valid user's session and the corresponding csrf token. The attacker may have his own appropriate account to log on, but then he could just perform the operation anyway. Or he may have a csrf token, but either unauthenticated, or to a lower privilege account. But he cannot have both, and that's the point.

So this protection basically validates that the request comes from a source that was actually rendered by the legitimate application and not somebody else.

Note that in this case, setting the token in a cookie is pointless, because the cookie will be sent automatically just like the session cookie.

Double posting

A different strategy is to generate a token, and set it as a cookie for the client. The client then reads the token from the cookie, and sends the same token as a request header as well. The server only compares whether the request header and the cookie contain the same token. This works, because an attacker cannot read the application token from a cookie set by a different origin (see SOP above), but the application on the legitimate domain can. So the client sending the request effectively proved that it is running on the legitimate application domain. The benefit of this is that the application is stateless, does not need a session. The drawback is that it is slightly less secure.

(Interestingly, the token in this case can even be generated on the client, it still works, because the attacker on his own domain cannot set or read an application domain cookie, but it is definitely less secure as it is a crypto operation in the browser.)

Checking referer or origin

As you correctly noted, another strategy could be to check the referer or origin of the request. It basically works, but is considered less secure. While double posting is considered secure enough for many applications, referer/origin checking is mostly not. There is a strong historical element to it I think, but still, it really is less secure.

There are many aspects of the problem, some that come to mind:

  • Sending the referer/origin header can be prevented by the attacker on his own domain. So the application would not know it was a different domain - it would just not have the info. You can of course implement it in a way that it needs a referer and/or origin, but that will lead to potential bugs and issues where browsers don't send it for some reason etc.
  • Referer and origin can be faked under some circumstances. For example old vulnerable browser plugins (Java, Flash... does anyone remember Flash still?) allowed setting any header, the attacker only needed to have one of these installed in the victim browser - and everybody had them.
  • Browser extensions can also set/modify headers, so an attacker might try to have his malicious extension installed by a victim user.
  • Origin is only set by modern browsers. Less of an issue now, most people use a browser that sets both referer and origin.

So for these reasons, simply checking referer/origin is not very robust, and another layer of protection should be in place.

SameSite cookies

A new invention by Google in Chrome is the SameSite attribute to cookies (in addition to the already existing and widespread httpOnly and secure cookie attributes). As of now, it is only supported by Chrome and not other browsers.

As said above, the underlying problem is that cookies (ie. the session cookie) gets sent to the server based on the request target, and not the origin. This means that if attacker.com server a page to a user and that page sends a post request from the browser to legitapp.com, any cookie set by legitapp.com will be sent to legitapp.com. So if it is a user logged in to legitapp.com visiting attacker.com, the existing session can be exploited.

This is changed by the SameSite cookie attribute, which makes a cookie not be sent in such cases when the originating domain is different from the target one. It can be set to 'strict' or 'lax', which basically determines the GET request behaviour, but with any of those will prevent CSRF on non-GET requests.

like image 157
Gabor Lengyel Avatar answered Oct 22 '22 08:10

Gabor Lengyel