Cross site request forgery is a kind of attack that aims on websites which allow their users to authenticate
permanently. Suppose that an attacker knows the structure of your application – he knows which HTTP
request to send to perform an action on behalf of logged-in user. All he has to do is to prepare an
<a> tag to click,
<img> tag to display or
views an email with his HTML code. It works because when a HTTP request is performed, the browser appends all cookies that
are used to identify a visitor, he can perform some action on behalf of the victim unnoticed.
The attacker does not need to access the cookie or session data (that should not be possible thanks to same origin policy of browsers). Attacker exploits the basic principles of HTTP communication.
<img> tag is especially tricky. An attacker can specify arbitrary URL as
src attribute. The browser
connects to that URL and expects to get an image, if the result of URL is not an image, the browser simply displays
image placeholder, but the action represented by that URL was already performed – therefore you should always use POST
method for modifications of data. The
<img> element can also be hidden to avoid attention.
Suppose that you have an application which allows users to register and login. The user has to enter an email address during registration so your application can send him password-reset email when he forgets it. Your application also allows to stay logged-in even if the user was not working with your application for several days.
Suppose that there is a form which allows the user to change his registration email without any confirmation (like entering current password or confirming the change of email from email message sent to original email address).
The password reset functionality simply generates new password and sends it to the current email address registered to an account.
The form can look like this (it is a change in database so it uses the POST method):
<form action="/change-email" method="post">
<input type="email" name="new-email">
Change my email
<form action="http://www.your-app.com/change-email" method="post" name="CSRF">
<input type="hidden" name="new-email" value="email@example.com">
//submit the form immediatelly
The attacker will probably generate unique email addresses because your application does not allow multiple accounts per one email.
Now he has to distribute this code to places where he can expect a lot of traffic (sites that are often visited by users of your application). He can exploit XSS vulnerability of other website or create his own website with such code and use spam email to attract visitors to it.
Once a user of your website visits a page with this automated form, the form submits which results in change of email address of visitor’s account (suppose that the visitor is also user of your application and he is logged-in at the time of the attack). The attacker can then use the password-reset functionality of your application to generate a new password and cut the user off his account. The generated password will obviously be delivered into attackers email account.
Unfortunately, the developer is:
OWASP mentions two basic means to protect users from CSRF attacks. First one is to check origin of the request and the second is to generate unique tokens for each action.
The origin of the request is usually passed in the
Referer HTTP header of a request. It tells the backend the URL
of the resource which is responsible for firing current HTTP request. E.g.: when you visit
page-a.com and click
a link leading to
Referer header will be
page-b.com request an image
page-b.com/images/img.jpg, the referer will be
page-b.com. When the
Referer header does not match your
domain, it is probably CSRF attack.
The token method is based on randomly generated large number which is stored in session data and has to be
submitted along with form data. Because the attacker cannot extract such data from your website (unless your
application allows to communicate with any host using AJAX requests – header
Access-Control-Allow-Origin: *), and
it is very hard to guess current token value, the request is not accepted.
It is better to use some framework with built-in CSRF protection or a library dedicated to this task than taking care of this all by yourself. There is a tutorial on CSRF protection for Slim framework.