Cross-Site Request Forgery (CSRF)

Definition

CSRF, also known as XSRF, Sea Surf, or Session Riding, is an attack that tricks an end user into performing unintended actions (of the attacker's choosing) on a web application they are currently authenticated to.

How CSRF Works

CSRF vulnerabilities allow attackers to circumvent the Same-origin policy (SOP) which is a security mechanism designed to prevent different websites from interfering with each other.

CSRF attacks are focused on changing state on the server e.g. changing login credentials, making purchases, transferring funds, etc. Attempting to retrieve data does NOT benefit the attacker since they cannot receive responses due to the SOP.

Some conditions need to be met for a CSRF attack to be successful:

  • A Relevant Action: There is an action within the application that the attacker has a reason to induce e.g. changing the user's email or password.

  • Cookie-based session handling: Performing the action involves issuing one or more HTTP requests, and the application relies solely on session cookies to identify the user who has made the requests. There is no other mechanism in place for tracking sessions or validating user requests. HTTP Basic authentication or certificate-based authentication can also work since the user's credentials are transmitted with every request.

  • No unpredictable request parameters: The requests that perform the action do not contain any parameters whose values the attacker cannot determine or guess. For example, when causing a user to change their password, the function is not vulnerable if an attacker needs to know the value of the existing password.

With these three conditions in place, a CSRF attack is possible. Let's discuss some examples of how these attacks can be carried out.

Types of CSRF Attacks

Alice wishes to transfer $100 to Bob using the bank.com web application that is vulnerable to CSRF. Maria, an attacker, wants to trick Alice into sending the money to Maria instead. The attack will comprise the following steps:

  1. Building an exploit URL or script

  2. Tricking Alice into executing the action with social engineering.

GET Scenario

If the application was designed to primarily use GET requests to transfer parameters and execute actions, the money transfer operation might be reduced to a request like:

GET http://bank.com/transfer.do?acct=BOB&amount=100 HTTP/1.1

Maria now decides to exploit this web application vulnerability using Alice as the victim. Maria first constructs the following exploit URL which will transfer $100,000 from Alice’s account to Maria’s account. Maria takes the original command URL and replaces the beneficiary name with herself, raising the transfer amount significantly at the same time:

http://bank.com/transfer.do?acct=MARIA&amount=100000

The social engineering aspect of the attack tricks Alice into loading this URL when Alice is logged into the bank application. This is usually done with one of the following techniques:

  • sending an unsolicited email with HTML content

  • planting an exploit URL or script on pages that are likely to be visited by the victim while they are also doing online banking (stored CSRF flaws --> amplifies severity).

The exploit URL can be disguised as an ordinary link, encouraging the victim to click it (if Alice clicks on the link while logged into her banking application, she will unknowingly initiate the transfer.):

<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">View my Pictures!</a>

Or as a 0x0 fake image:

<img src="http://bank.com/transfer.do?acct=MARIA&amount=100000" width="0" height="0" border="0">

If this image tag were included in the email, Alice wouldn’t see anything. However, the browser will still submit the request to bank.com without any visual indication that the transfer has taken place. This is because the image tag automatically generates a GET request to the image link declared in the img src attribute.

POST Scenario

The only difference between GET and POST attacks is how the attack is being executed by the victim. Let’s assume the bank now uses POST and the vulnerable request looks like this:

POST http://bank.com/transfer.do HTTP/1.1

acct=BOB&amount=100

Such a request cannot be delivered using standard A or IMG tags, but can be delivered using a FORM tags:

<form action="http://bank.com/transfer.do" method="POST">

<input type="hidden" name="acct" value="MARIA"/>
<input type="hidden" name="amount" value="100000"/>
<input type="submit" value="View my pictures"/>

</form>

This form will require the user to click on the submit button, but this can be also executed automatically using JavaScript:

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

<form...

NB: Stored CSRF flaws: a CSRF attack can also be stored in the vulnerable site itself e.g. by storing an 'img' or 'iframe' tag in a field that accepts HTML, or by using an XSS attack. This amplifies severity since the victim is more likely to view a page containing the attack, than a random page on the internet.

Other HTTP Methods

Modern web application APIs frequently use other HTTP methods, such as PUT or DELETE. Let’s assume the vulnerable bank uses PUT that takes a JSON block as an argument:

PUT http://bank.com/transfer.do HTTP/1.1

{ "acct":"BOB", "amount":100 }

Such requests can be executed with JavaScript embedded into an exploit page:

<script>
function put() {
    var x = new XMLHttpRequest();
    x.open("PUT","http://bank.com/transfer.do",true);
    x.setRequestHeader("Content-Type", "application/json");
    x.send(JSON.stringify({"acct":"BOB", "amount":100})); 
}
</script>

<body onload="put()">

Fortunately, this request will not be executed by modern web browsers thanks to same-origin policy restrictions. This restriction is enabled by default unless the target web site explicitly opens up cross-origin requests from the attacker’s (or everyone’s) origin by using CORS with the following header:

Access-Control-Allow-Origin: *

Testing for CSRF

A CSRF vulnerability is fairly simple to spot. Use the following tips:

  • Look for a form that is not sending an extra token i.e., csrf_token, csrf, token.

  • Is the form also NOT asking for confirmation of an action? e.g. to change password please provide the current password.

  • Is the CSRF generating impact? e.g. change email, send payment.

  • You can escalate a CSRF bug using business logic or XSS.

CSRF Bugs in the Wild

Prevention and Mitigations

Primary Defense

CSRF Token

The most robust way to defend against CSRF attacks is to include a CSRF token within relevant requests. The token should be:

  • Unpredictable with high entropy, as for session tokens in general.

  • Tied to the user's session.

  • Strictly validated in every case before the relevant action is executed.

Furthermore, the token should be transmitted securely through:

  • Hidden field of an HTML form that is submitted using a POST request.

  • A custom request header.

An alternative approach, of placing the token into the URL query string, is somewhat less safe because the query string:

  • Is logged in various locations on the client and server side;

  • Is liable to be transmitted to third parties within the HTTP Referer header; and

  • can be displayed on-screen within the user's browser.

The token should not be transmitted within a cookie.

How should the CSRF token be validated?

  • Generated tokens should be stored server side within the user's session data.

  • When performing a request a validation should be performed that verifies that the submitted token matches the value that is stored in the user's session.

  • Validation should be performed regardless of HTTP method content type of the request.

  • If a token is not submitted, the request should be rejected (and logged).

Additional Defense

SameSite Cookies

An additional defense that is partially effective against CSRF, and can be used in conjunction with CSRF tokens is SameSite cookies.

Insufficient Defense

Referer Header

The Referer HTTP header contains an absolute or partial address of the page making the request.

However, referer headers can be spoofed.

This defense can be bypassed in the following ways:

  • If it is not present, the application does not check for it.

  • The referer header only checks to see if it contains the domain and exact match is not made.

How We Can Protect Ourselves

Most modern web frameworks come with built-in protections against CSRF. Developers should ensure they enable them.

On the user side, we can do the following to protect ourselves:

  • Logging out of sensitive applications before visiting another.

  • Periodically clearing our cookies and browsing history.

  • Not clicking on suspicious links we receive via email, forum sites, social media, etc.

Further Research

Find out how to carry out CSRF attacks in the age of JSON in the request body.

References

Update

Chrome recently updated, and people have been saying that this is the death of CSRF as a vulnerability. What did Chrome 80 change and why is it going to impact CSRF so badly? TL;DR: All cookies without a SameSite attribute will now by default be sent with SameSite=Lax, this restricts the ability for cookies to be sent in a third party or cross-site context.

Last updated

Was this helpful?