Decoding and preventing the Cross-Site forgery (CSRF) attacks

Cross-site request forgery (CSRF) attacks a web vulnerability in which a hacker tricks a privileged or authorized user into performing an action that could result in fraudulent payment, providing or revoking accesses, deleting important files, etc occurring on malicious websites, emails, blog, instant message.

Cross site request forgery attack

How do CSRF attacks take place?

Unlike cross-site scripting attacks, CSRF does not involve running any malicious code on our website, in this type of attack, the hacker takes advantage of the server-side loopholes that perform actions on the trust that the request is made by authorized users and the hacker tricks the users in trigger action like clicking on a link in the email or trigger an action to an URL where you could be logged and already authorized making use of your cookies and session.

Because browser requests automatically contain all cookies, including session cookies, CSRF attacks are effective. As a result, even if the user has verified with the website, the website is unable to discern between authenticated requests that are counterfeit and those that are actually authorized.

The outcome of the CSRF attack depends upon the privileges of the users on whose behalf the action is being performed.

Forgery with HTTP Get request

For example, assume you are logged into your hosting account https://my-web-hosting.com, now when you are logged in, the cookies store the session details to avoid authentication every time.

A hacker knows that your session is maintained in the browser and they have found a vulnerability that a get request https://my-web-hosting.com/delete?file=’config.yml’ is used to delete files for the authorized users as your website does not make a second confirmation before completing an action.

They trick the user by sending emails with lucrative things that could make them click on the links, now the label of the link could be Join my group but the URL will point to your hosting website.

<a href=”https://my-web-hosting.com/delete?file=’config.yml’”>Join my group</a>

Clicking on this link would result in deleting files that could compromise your hosting website as the cookies are already stored and the browser will attach it to the request making it authorized to perform the action.

The same can happen with a banking site, where the hacker can trick people into making transactions without their knowledge.

That is why you will notice that many financial websites opt for multi-confirmation before taking any important actions. Also, they expire the sessions frequently to avoid security issues.

The get request is often overlooked from the security perspective and found to have lots of vulnerabilities.

A hacker does not even have to make you perform an action as the get request can be made without your acknowledgment.

For example, in the email, the hacker will load an image with the height and width of 0 X 0 making it visible, but the image’s src will be a get request that will be made when the email is opened.

<img src=”https://my-web-hosting.com/delete?file=’config.yml” width=”0” height=”0”/>

Video and audio tags can also be used to load the URLs (certain browsers load the source on the human interaction thus image tag is most preferred).

Forgery with HTTP POST and other requests

The cross-site forgery can also occur with the POST or any other HTTP method from a form.

Let’s assume that the hacker has found a vulnerability in the post request that can be exploited by tricking the user into performing certain actions.

The hacker creates a form with few hidden fields with the data that could cause harm and normal fields to make it look legitimate.

<form method="post" action="https://my-web-hosting.com/delete">
   <input type="hidden" name="file" value="config.yml" />
   <input type="text" name="username" />
   <input type="text" name="password" />
   <input type="submit" value="submit" />
 </form>

Once user fills the details and submits the data a request would be made that could delete your file.

This too does not require any human action and can be pulled behind the scenes as well when the document loads.

<body onload="document.forms[0].submit()">
....

The form can be hidden on the email.

How to prevent CSRF attacks from taking place?

There are multiple best practices that can be followed to prevent CSRF attacks but if your website is under XSS attack then all these mitigation techniques will become useless.

Using token to prevent CSRF attacks

In a server-side rendered application or application that maintains the state, the server can generate a unique secure token that could be passed to the client in each response, which would be returned to the server in the next request which could be verified to make sure that the request is authentic.

If the token does not match, then the request can be rejected.

This token can be unique for each request or session and is different from the authentication tokens.

A framework such as .Net provides this inbuilt.

This token should not be passed in cookies, rather it can be passed in the hidden fields of the forms or in the request header.

Since requests with custom headers are inherently subject to the same-origin policy, it is deemed more secure to insert the CSRF token via JavaScript in a custom HTTP request header as opposed to inserting it in a hidden field form parameter.

To pass them in the request header, the cookie that brings the token from the server should not be with the httpOnly flag as the cookie is read through Javascript and then it will returned in the header.

This cookie-to-header implementation is more suitable for the client-side rendered application and frameworks such as Angular and Django use it.

Double Submit Cookie Method

Case where maintaining the state is a problem, a double submit cookie pattern can be used which is stateless and very easy to implement. There are two variations to it of which Naive is the easiest to implement.

Naive Double Submit Cookie

It is one of the initial techniques that is easy to scale and implement. In this approach, a random value is sent as a request parameter and in a cookie, and the server compares the values to see if they match. The website should produce a (preferably cryptographically strong) random value when a user visits (even before authenticating to prevent login CSRF) and set it as a cookie on the user’s computer apart from the session identifier. The website then mandates that this random number be included in the request header or as a hidden form value in every transaction request. The server will accept the request as authentic if both of them match; if not, it will refuse the request.

During a cross-site request, the attacker won’t be able to get its hands on the cookie making it impossible to match with the random value.

Single Double Submit Cookie

A secret key used in the Signed Double Submit Cookie is only known by the server. By doing this, it is made impossible for an attacker to generate and insert a known CSRF token into the victim’s authorized session. Tokens can be safeguarded using encryption or hashing.

To further improve security in both scenarios, it is advised to connect the CSRF token to the user’s active session.

Custom and unique request headers

All the above techniques are effective in scenarios where the data is submitted through a form. But in modern web applications, forms are hardly utilized especially on the client-side rendered applications.

The data can be collected in the input fields and can be directly passed in asynchronous (Ajax) requests as JSON or in any other format.

In this case, we can make use of the custom request header which does not make use of tokens. It is simple to use and implement.

An arbitrary and unique header with a random value is passed in the request that has to be secured and requires CSRF protection.

The request checks for this header and rejects the requests that expect this header and are not present.

This defense is based on the same-origin policy (SOP) limitation of the browser, which states that a custom header can only be added by JavaScript and only within its origin. JavaScript is not permitted to send cross-origin requests with custom headers by default in browsers. These headers can only be added by JavaScript that you serve from your origin.

The advantage of using this is that it does not require any UI changes on the client side and no state has to be maintained on the server side as no token is returned that has to be validated.

Utilize CORS headers along with the custom headers to double-proof the CSRF attacks.

By default, cross-origin requests, or CORS, do not set cookies. To enable cookies on an API, you need to specify Access-Control-Allow-Credentials=true. The browser will reject any response that contains Access-Control-Allow-Origin=* if credentials are permitted. To allow CORS requests while protecting against cross-site request forgery (CSRF), make sure the server uses the Access-Control-Allow-Origin header to whitelist only a few particular sources that you have total control over. Any cross-origin request originating from an allowed domain has the ability to set custom headers through JavaScript.

Conclusion

Cross-site forgery can be prevented by following the best practices such as enabling the two-factor authentication and confirmation on the critical actions, restricting the session durations and expiring them on certain attempts.

Also, many cookies-related configurations can be utilized to restrict the access of cookies when the request is triggered from a different origin.