CSRF (Cross-Site Request Forgery, aka one-click attack) is an attack that tricks a web browser into performing an unwanted action within an application, which a victim is logged into. If a victim visits a website created by an attacker, a request is sent secretly on behalf of a user to another server that performs a malicious action.
To make this attack possible, a victim has to be authenticated on the server to which the request is sent. This request should not require any confirmation, which can’t be ignored or tampered with an attacking script.
A forged request is sent to a target website through a victim’s browser. An application can’t distinguish a legitimate request from a malicious one since a user is authenticated in the application during the attack.
The severity of the vulnerability exploitation is dependant on a user’s access privileges. A successfully conducted CSRF attack will trick a common user into making state change requests (fund transfers, changed email and password, etc.). If a victim is an administrator, the attacker will be able to compromise an entire web application.
What does CSRF look like?
There are several ways to propel a user into CSRF and make them send data to a web application. For starters, an attacker creates a valid malicious request. Let’s say, for instance, our victim Alice is going to transfer $100 to Bob through a vulnerable web application — bank.com. So, attackers want money to be transferred to their account.
If an application utilizes GET requests for sending parameters and performing its actions, a funds transfer operation can look as follows:
GET http://bank.com/transfer.do?acct=BOB&amount=100 HTTP/1.1
Now, the attackers create a URL exploit, which will transfer $100,000 from Alice’s account to theirs. The URL will look as follows:
The attackers trick Alice’s browser into following the crafted link. There are several ways to achieve this:
- Inject a link that Alice will most likely click on;
- Use a link as a resource that will be loaded by the browser.
The URL can be masked as a common link:
<a href="http://bank.com/transfer.do?acct=ATTACKER&amount=100000">View my Pictures!</a>
or a 0x0 image:
<img src="http://bank.com/transfer.do?acct= ATTACKER&amount=100000" width="0" height="0" border="0">
If this image tag is added to the letter, the victim won’t notice anything. If the victim is authorized, while attempting to download the image, the browser will insert cookies and send a request to the server. The server, in its turn, will execute the request on behalf of the user.
Other types of requests are vulnerable as well. For example, POST requests can be exploited with auto-submit. Let’s assume, a bank uses POST, and a vulnerable request looks this way:
POST http://bank.com/transfer.do HTTP/1.1
Such a request can’t be delivered in the standard
IMG tags. However, it can be done with the help of the form tag:
<form action="http://bank.com/transfer.do" id="csrf" method="POST">
<input type="hidden" name="acct" value="MARIA"/>
<input type="hidden" name="amount" value="100000"/>
<input type="submit" value="View my pictures"/>
This form may require a user to click the send button, or the process can be fully automated:
var http = new XMLHttpRequest();
http.open('POST', '/transfer.do', true);
It is necessary to check if there is a CSRF token in the request that executes this or that action.
- If there is no token, an attacker can perform the CSRF attack.
- If the request has a token, make sure that the token is validated. To do it, delete or modify the token. Then, if the request is successfully executed and the result is the same as with the original token, it means that tokens are not validated and the CSRF attack is possible.
To protect the application from CSRF, it’s necessary to add an extra parameter (a token) with a random value unknown to the adversary. The browser inserts a token into every request of the user.
For example, we had the following request:
POST /transfer.do HTTP/1.1
Then we added a unique CSRF token:
POST /transfer.do HTTP/1.1
Now a request without a token or with a token that doesn’t match the current user session will be blocked at the server-side.
If a session cookie is marked as a Same-Site cookie, it is sent only with the requests made from the same domain. Thus, requests from other websites will not be executed.