CSRF - A Sleeping giant in the world of web security

Ashif Mohamed
10 min readOct 4, 2018

--

Before going deep in to the concept of Cross Site Request Forgery , think of an instance where you clicked a suspicious link received via an Email or chat. Well , if that’s the case, you might have become a victim of CSRF attack. How this happens, the after effects of these attacks and prevention techniques is what this guide is all about. We will examine another common, but often overlooked attack,Cross Site Request Forgery (CSRF), which exploits a website’s assumption that all requests that originate from a user’s browser are in fact those of the user.

Exploiting CSRF attack

Introduction to CSRF

Cross Site Request Forgery (CSRF), Sea Surf, or XSRF for short, is considered a sleeping giant in the world of web security, due to the fact that it may not be taken as seriously as it should, even though it can prove to be a powerful attack,which is why it has secured its spot on OWASP ’s Top 10 list several times in a row. It exploits a website’s assumption that all requests that originate from a user’s browser are in fact those of the user. It is a tactic that has been used in real-world attacks against PayPal and gmail, just to name a few. PayPal Send Money Cross-Site Scripting Vulnerability potentially allows an attacker access to a victim’s PayPal account. This is one of the few scenarios which reminds us how dangerous a successful CSRF attack could be.This being said,CSRF attacks have a major limitation. CSRF only allows for state changes to occur and therefore cannot cater attacks that require the attacker receiving the contents of the HTTP response.

Why use CSRF ?

Any application that allows a user to send or update data is a potential target for an attacker. The following is a list of potential uses for CSRF:

  • Change a user account email password.
  • Transfer funds from one bank account to another.
  • Change the delivery address of an order.
  • Use a content management system to update content from a website.

Changing a user account email with CSRF

Many websites often allows a user to change his or her email address. This email address change could be made in one of two ways. Either by sending data via URL parameters where a HTTP GET request is used or sending data via forms where HTTP POST is used.

There are two main parts to executing a CSRF attack, the first part being to trick the victim into clicking a link or loading up a page. This is normally done through social engineering which works exceptionally well into leveraging a victim’s curiosity to click on malicious links. The second part is to send a crafted request in the victim’s browser, that will send a legitimate looking request to the web application.

In the CSRF attack example below, the data to be changed is contained in a parameter called “EmailAddress”. If the user can be tricked into clicking a link or visiting a page under the attacker’s control, the following code can be used to change the email address stored as a login credential on that site:

CSRF-GET request code snippet

Imagine the website only allows updates via POST, still the email address can be changed. it just requires some different code:

CSRF-POST request code snippet

Once the email address is changed, then it’s as simple as using the built-in forgot password facility that most websites have. If a password change link or changed password is sent directly to the registered email address, it will then be mailed to the attacker and the user account is compromised.
The most important factor here is that the user must be logged in to the relevant website at the time he or she is tricked into visiting the malicious page. However, many sites have a “keep me logged in” facility, which makes them vulnerable to the attack.

Arresting CSRF attack

As a general standard, CSRF defense can be carried out using two checks without user intervention.

  1. Examine the standard headers.
  2. Verify CSRF token.

Ideally, both these methods would be combined to defend against a CSRF attack. The first method involves verifying whether a request is from same origin with standard headers and act accordingly. For this, we should determine both the Target origin & Source origin so that you can simply compare the two values and if they don’t match you know you have a cross-origin request. It is generally impossible for an attacker to spoof any header in the victim’s browser during a CSRF attack, except via an XSS vulnerability. However, a clever attacker can forge the content of the Source origin header, thus circumventing this defense. A better method is to send a unique identifier (CSRF token) with each request, a tactic employed during application development. Now let’s see how CSRF defense could be done using CSRF tokens.

Using CSRF tokens for defense

This second check involve custom defense mechanisms using CSRF specific tokens (a secure random token) created and verified by your application. This can be done using approaches that do not require any server side state and vice versa.

  • Synchronizer Tokens (requires server side state).
  • Double Submit Cookie.
  • Encrypted Token Pattern.
  • Custom Header.

Note that, among the methods mentioned above:only Synchronizer Tokens use a server side state approach to verify a CSRF token. In the next section we will look how both these approaches can be used in your application. Refer the OWASP CSRF Prevention Cheat Sheet page For further facts regarding CSRF defense.

Double Submit Cookie

A double submit cookie is defined as sending a secure random value in both a cookie and as a request parameter, with the server verifying if the cookie value and request value match. The site does not have to save this value in any way, thus avoiding server side state.

Double Submit Cookie Process

Double Submit Cookie works as follows:

  1. The web server generates a token.
  2. The token is saved in a Cookie in user’s browser.
  3. The token is set as a hidden input on the protected form.
  4. A request is sent by the user.
  5. The token is included in the request .
  6. The web application compares the token saved as a cookie with the token sent through the request.
  7. If these tokens match, the request is valid, as it has been sent through the actual form in the web application.
  8. Else there is no match, the request will be considered as illegal and will be rejected.

Double Submit Cookie protects the form against CSRF attacks, because an attacker crafting a request will also need to guess the CSRF token saved as a cookie for them to successfully trick a victim into sending a valid request.

Synchronizer Tokens

One of the most popular implementation to prevent CSRF, is to make use of a challenge token that is associated with a particular user and can be found as a hidden value in every state changing form which is present on the web application. This token, called a Synchronizer Token. This is similar to a Double Submit Cookie approach except the fact that this requires server side state since the CSRF token is stored in the server side.

Synchronizer Token Process

In general, developers need only to generate this token once for the current session. After initial generation of this token, the value is stored in the session and is utilized for each subsequent request until the session expires. When a request is issued by the end-user, the server-side component must verify the existence and validity of the token in the request as compared to the token found in the session. If the token was not found within the request or the value provided does not match the value within the session, then the request should be aborted.

Are you safe now ?

Well, you are safe until an attacker is not aware of the generated token. But what happens if the attacker gets the token. Cross-Site Scripting (XSS) is one method that an attacker can use to do this. XSS is not necessary for CSRF to work. However, any cross-site scripting vulnerability can be used to defeat token, Double-Submit cookie and standard header checks CSRF defenses. This is because an XSS payload can simply read any page on the site using a XMLHttpRequest and obtain the generated token from the response, and include that token with a forged request. It is required that no XSS vulnerabilities are present to ensure CSRF defense.See the OWASP XSS Prevention Cheat Sheet for detailed guidance on how to prevent XSS flaws.

In the next section we will discuss on implementing CSRF specific defense in your application.

Code your solution for CSRF attack

CSRF defenses have been built into many frameworks, so i strongly recommend using them first when they are available. But in order to get an understanding about how it’s done, I will be showing you the sample applications that i implemented in Java Spring-Boot with Double Submit Cookie and Synchronizer Tokens defense techniques.For demonstration purpose i have used the Email changing example explained in the previous section.

1 : Double Submit Cookie Implementation

As i have already explained the flow of how this happens. Let’s straightaway shift to the coding part. Note that only the parts relevant for demonstration is shown. You can get the full implementation code here .

The above code snippet shows what happens when a user tries to login to the system. If a user is successfully authenticated, two cookies are stored with current SessionId & the CSRF token respectively. In order to generate unique random numbers i have used UUID (Universal Unique Identifier) generator in java. After a successful login, user is redirected to his Account page from where he could send an Email change request. The process of appending a hidden input with value of the cookie having CSRF token, is done when loading the Account page. Below code shows how it’s done:

<script> 
$(function () {
let csrfToken = getCookie();
console.log(csrfToken);
let hiddenInput = '<input type="hidden" name="csrfToken" value="' + csrfToken + '">';
$(`#form-elem`).append(hiddenInput);
});

function getCookie() {
let name = "csrfCookie=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1); }
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length); }
}
return "";
}
</script>

In the Account page, when a user submits a request to change the email address, the hidden input with CSRF token value is also sent along with the request. Server then checks whether the CSRF token obtained from the request is equal to the one in the CSRF cookie.

Below code snippets will show the implementation of the methods used in both the Controller classes shown above.

Screenshots of the sample application is shown below. Observe the outputs to see when the CSRF token is generated and appended to a form.

Sample output showing different Email change responses

In the final output screenshots, you can see that the email change request gets aborted when the original CSRF token is changed,or in other words, if it’s different from the value in CSRF cookie.

Note: In the final image shown above, I have changed the hidden input value manually by inspecting that element. In the real world it could be an Attacker who would forge a request. Your application would be safe as long as the attacker is not able to get the original CSRF token value stored as a cookie.

2 : Synchronizer Tokens

Implementation of Synchronizer Tokens is same as the Double Submit Cookie except that here, the CSRF token not stored as a cookie. Rather it is stored in the server. Therefore, in order to get the CSRF token stored in the server, we should define a GET request which would return the CSRF token of the current user. If you want to append the token inside a form, you would call this GET request using ajax when the page loads.

<script>
$(function () {
console.log(“came”);
$.ajax({
type: “GET”,
url: ‘/get-token’,
success: function (data) {
console.log(data);
appendInput(data);
},
error: function (data) {
}
});
});

function appendInput(csrfToken) {
let hiddenInput = ‘<input type=”hidden” name=”csrfToken” value=”’ + csrfToken + ‘“>’;
$(`#form-elem`).append(hiddenInput);
}
</script>

Above code shows the code that is executed when the Account page loads after a user is logged in. The “/get-token” GET request is called here.

@RestController
public class CSRFController {
@Autowired
SynchronizerService synchronizerService;
@GetMapping(“/get-token”)
public ResponseEntity<String> getCSRFToken(){
System.out.println(synchronizerService.getCSRFServerToken());
return ResponseEntity.ok(synchronizerService.getCSRFServerToken());
}
}

Above code shows what happens when a “/get-token” request is called. This would return the CSRF token stored in the server as the response. The “getCSRFServerToken()” method will check whether a token exists for the current session and would return the token if there any.

Apart from these major code changes. There would be some other minor ones which differs from the implementation of Double Submit Cookie such as, not generating a Cookie for the CSRF token. See here for the full implementation.

Conclusion

CSRF attacks can be used on a wide-range of sites. Any site where data can be altered is a potential target. Implement the fixes detailed above, and your website will be much more secure against this attack.

--

--