What is cross-site request forgery?
What is cross-site request forgery? Cross-site request forgery attacks (CSRF or XSRF for short) are used to send malicious requests from an authenticated user to a web application. Learn how CSRF attacks work and what we can do to prevent them.
Your Information will be kept private.
Your Information will be kept private.
Cross-site request forgery attacks (CSRF or XSRF for short) are used to send malicious requests from an authenticated user to a web application. The attacker can’t see the responses to the forged requests, so CSRF attacks focus on state changes, not theft of data. Successful CSRF attacks can have serious consequences, so let’s see how CSRF works and how you can prevent it.
Legitimate Cross-Site Requests
When you are browsing a website, it is common for that website to request data from another website on your behalf. For example, in most cases, a video that is shown on a website is not typically stored on the website itself. The video appears to be on the website but is actually being embedded from a video streaming site such as YouTube. That’s the idea behind Content Delivery Networks (CDNs), which are used to deliver content faster. Many websites store scripts, images, and other bandwidth-hungry resources on CDNs, so during browsing, images and script files are downloaded from a CDN source rather than the website itself.
While this improves the browsing experience, it might also be a source of a security problem if a website asks the web browser to retrieve data from another website without the user’s consent. If such requests are not handled correctly, an attacker can launch a cross-site request forgery attack – a type of attack that has made the OWASP Top 10 list of most critical web application security flaws several times.
How Can Cross-Site Requests Be Dangerous?
When a website requests data from another website on behalf of a user, there are no security concerns as long as the request is unauthenticated, i.e. the session cookie is not sent. However, when the user’s session cookie is sent with the request, attackers can launch a cross-site request forgery attack that abuses the trust relationship between the victim’s browser and the web server.
Combined with social engineering to persuade users to open a malicious link, CSRF attacks can have serious consequences – but how exactly do they work? Before we discuss CSRF vulnerabilities, let’s start with an overview of HTTP requests, cookies, and user sessions.
A Quick Introduction to HTTP Requests and Cookies
HTTP GET Requests
HTTP GET requests are used to request data from the web server. For example, when you enter a website URL in your web browser, you instruct the browser to send an HTTP GET request to the web server that hosts the website. The server then returns the response, and the browser renders it.
HTTP POST Requests
HTTP POST requests are used to send data to be posted on the web application. For example, when you submit a web form, such as a login or contact form, your browser generates an HTTP POST request. The request contains data submitted through the web form.
Automatically Generated HTTP GET and POST Requests
Sometimes, GET and POST requests are triggered automatically by certain HTML tags or by JavaScript, so they don’t always require user interaction. For example, the <img>
tag automatically generates a GET request to the image link declared in the img src
attribute. Another example is an XHR POST request (AJAX request), used to automatically fetch search suggestions while the user is typing a query.
Web and Session Cookies
Websites use cookies to identify a user, or to retain a user’s logged in session on the website. Session cookies typically contain a unique ID, which is an identifier the web application uses to identify a particular logged in user. Therefore, when a cookie is set for a specific website, the web browser sends it along with every HTTP request it issues to that website to retain the logged in session. However, this is not just a matter of session cookies. Using CSRF, an attacker can also issue requests on behalf of a user who uses NTLM or Basic Auth for authentication, even if the web server recognizes him based on his IP address.
How Does Cross-Site Request Forgery Work?
Since cross-site requests do not need your permission, an attacker can abuse this and send requests without your consent and without you noticing. Let’s take a look at the following scenario which highlights why this can be a problem.
A Legitimate Web Form
Imagine a form on a website that allows you to change your email address. To change it, all you have to do is write your new address into an input field and click “Change” while you are logged in. If you are not logged in, you do not have a session cookie, and the form won’t work. Let’s see how this input field works by looking at the underlying HTML code:
<body>
<p>Your new email address</p>
<form method="POST" action="mail.php">
<input type="text" name="email"
placeholder="Change your email address">
<button type="submit">Change</button>
</form>
</body>
In the web form code above, there are three important HTML attributes: method
, action
and name
.
The method
Attribute
The method
HTML attribute is used to specify which HTTP verb to use, and by default it is GET. When GET is used, all the parameter-value pairs are sent as part of the request in the URL, therefore appearing in the browser bar right after the question mark character, such as:
https://www.example.com/mail.php?email=alice@example.com
Such requests are logged in the web server’s log files and in the browser history. Therefore, the GET verb should only be used to transmit non-sensitive information and for actions that don’t change data (so no insert, update, or delete). For example, it could be used to indicate the page you are currently browsing, such as ?page=home
.
In web forms, typically the HTTP verb POST is used, because it sends the data in the body of the request. Therefore there is no record of the data being sent in server logs or browser history. This makes it ideal for transmitting sensitive and large amounts of data, such as passwords.
The action
Attribute
The second HTML attribute is called action
, in which the target of the request is specified. This can either be a page on the website or an external one, on another domain. The value in the above code sample is mail.php
, which is the name of the PHP script that allows you to change your email address.
The name
Attribute
The name
attribute in the web form’s input field that contains the name of the parameter in which the data you submit will be stored. Therefore, if you type in alice@example.com in the form and click the submit button, the value of the parameter mail
will be set to alice@example.com
and the web server will receive the following parameter-value pair:
mail=alice@example.com
The HTTP POST Request
When the form is submitted, the browser sends the following HTTP request:
POST /email.php HTTP/1.1
Host: example.com
Cookie: SESSION=e29a31e41c9512a4bd
Content-Type: application/x-www-form-urlencoded
mail=alice@example.com
As you can see, there is a Host
HTTP header containing the hostname of the website the form is submitted to. There is also a Cookie
HTTP header containing the session cookie value which the web application uses to determine if you are logged in.
Abusing Web Forms in a Cross-site Request Forgery Attack
Create a Copy of the Web Form
With the above knowledge, it is easy to think of a scenario in which an attacker can change your email address to something of his choice. He can copy the web form and host it on his own web server, such as http://www.attacker.com/evil.php
. Below is an example of the new form:
<form id="csrf" method="POST" action="http://example.com/email.php">
<input type="text" name="mail" value="bob@attacker.com">
<form>
<script>
document.getElementById('csrf').submit();
</script>
The self-submitting form is then placed at https://attacker.com/csrf.html
.
From the code above, you can also notice that the form does not have a “Submit” button, so the attacker can trigger the web form without the user’s knowledge or consent. Instead of a button, we have one line of JavaScript:
document.getElementById('csrf').submit();
This JavaScript code first selects the form element and then submits the form. Once the form is submitted, the victim’s email address is changed to bob@example.com
, as set in the value
attribute in the code above.
The Attacker’s HTTP Request
Below is the HTTP Post request that was generated by the attack. We’ve removed some unrelated request headers so it is easier to read:
POST /email.php HTTP/1.1
Host: example.com
Origin: http://attacker.com
Referer: http://attacker.com/csrf.html
Cookie: SESSION=e29a31e41c9512a4bd
Content-Type: application/x-www-form-urlencoded
mail=bob@example.com
Here is a breakdown of the attacker’s HTTP POST request:
- The web browser issues a POST request.
- The host is the vulnerable website the user is logged in to, in our case
example.com
. Note theOrigin
andReferer
headers that show where the request is coming from – the referrer isattacker.com
. - The
Cookie
header, which contains the user’s session cookie. Even though the browser request was initiated by a malicious script, the browser still sends theCookie
header along with the request because the request is forexample.com
, for which the user has a session cookie. This also means that the web application will recognize the user’s authorized session. - Below the cookie header is the
Content-Type
HTTP header which shows that the request was issued by a form. - And at the bottom, as the post body, is the parameter-value pair. The parameter is
mail
and the value is the one set by the attacker:bob@attacker.com
.
Tricking Victims Into a CSRF Attack
How can attackers trick their victims into a CSRF attack? Let’s assume the attacker publishes the form on https://attacker.com/csrf.html
. All he needs to do now is trick the user into navigating to the malicious website. This usually involves a little social engineering, for example sending a phishing email asking the victim to urgently visit this URL to restore access to their bank account.
So once the user visits https://attacker.com/csrf.html
, the form submission is triggered. The vulnerable website https://example.com
accepts the request and the email is changed to bob@attacker.com
, since to the web application it seems like the victim submitted the form (because of the session cookie).
Now all an attacker has to do is use the password reset functionality to send a password reset email. Since the email was changed to bob@attacker.com
, Bob will receive the email and can easily change Alice’s password to lock her out and take over her account.
Hiding the CSRF Attack from the Victim
For the victim not to notice the CSRF attack, the attacker can create another web page, for example info.html
, which contains information about a topic the victim is interested in. However, the web page controlled by the attacker can contain a hidden iframe pointing to https://attacker.com/csrf.html
. When the user visits info.html
, the form on csrf.html
is automatically triggered, without any visible indicator to the victim.
Attackers typically use CSRF attacks in login forms, such as password or email change forms, to hijack their victims’ accounts or create a new admin user on a web application.
How to Prevent Cross-Site Request Forgery Attacks
An attacker can launch a CSRF attack when he knows which parameters and value combination are being used in a form. Therefore, by adding an additional parameter with a value that is unknown to the attacker and can be validated by the server, you can prevent CSRF attacks. Below is a list of some of the methods you can use to block cross-site request forgery attacks.
Implement an Anti-CSRF Token
An anti-CSRF token is a type of server-side CSRF protection. It is a random string that is only known to the user’s browser and the web application. The anti-CSRF token is usually stored inside a session variable. On a page, it is typically in a hidden field that is sent with the request.
If the values of the session variable and the hidden form field match, the web application accepts the request. If they do not match, the request is dropped. In this case, the attacker does not know the exact value of the hidden form field that is needed for the request to be accepted, so he cannot launch a CSRF attack. In fact, due to same origin policy, the attacker can’t even read the response that contains the token.
Use the SameSite Flag in Cookies
The SameSite flag in cookies is a relatively new method of preventing CSRF attacks and improving web application security. In the above scenario, we saw that https://attacker.com/
could send a POST request to https://example.com/
together with a session cookie. This session cookie is unique for every user, so the web application uses it to distinguish users and to determine if they are logged in.
If the session cookie is marked as a SameSite
cookie, it is only sent along with requests that originate from the same domain. Therefore, when https://example.com/index.php
wants to make a POST request to https://example.com/post_comment.php
, it is allowed. However, https://attacker.com/
can’t send POST requests to https://example.com/post_comment.php
, since the session cookie originates from a different domain, so it is not sent along with the request.
Vulnerability Classification and Severity Table
Classification | ID / Severity |
---|---|
PCI v3.2 | 6.5.9 |
OWASP 2013 | A8 |
OWASP 2017 | A5 |
CWE | 352 |
CAPEC | 62 |
WASC | 9 |
HIPAA | 164.306(a) |
ISO27001 | A.14.2.5 |
Invicti | Low |