• Deutsch
  • English

All your pants are in danger - CSRF explained

Cross Site Request Forgery (CSRF) is a common form of attack against a web application. This post tries to shed some light on how it works and how exploits can be crafted. We will tailor this to a Drupal use case and example code.

Some general considerations:

  • First, keep in mind how web browsers and authentication works: if you are logged-in on a site with cookies, then your browser will always send along the cookies with any request it makes to that site. If another site embeds resources from that site (images, javascript, iframes ...), then the resource will be requested with your cookies attached.
  • Second, it is important to know that CSRF can only be applied to write operations. That means that a page callback must change the application's data. Example: the path /node/1 cannot be vulnerable to CSRF exploits in a standard Drupal installation, because a node is only displayed and not changed.
  • Third, you must know that a CSRF attack is always performed on behalf of a particular user. That means that the attack is performed "blindly", which means that the original attacker cannot access the response during the attack.

Confused? Me too, let's look at a "real" Drupal example.

The simple GET case

This pattern is probably most widely known among developers. Here's example module code that provides a menu callback to delete some example pants data:

<?php
/**
* Implements hook_menu().
*/
function mymodule_menu() {
 
$items['mymodule/pants/%/delete'] = array(
   
'title' => 'Delete pants',
   
'page callback' => 'mymodule_delete_pants',
   
'page arguments' => array(2),
   
'access arguments' => array('delete pants objects'),
  );
  return
$items;
}

/**
* Page callback to delete pants.
*/
function mymodule_delete_pants($pants_id) {
 
db_delete('mymodule_pants')->condition('pants_id', $pants_id)->execute();
 
drupal_set_message(t('Deleted pants %id', array('%id' => $pants_id)));
}
?>

Pretty straight forward, right? What could possibly go wrong with that code? The menu entry is protected with a permission, so everything is fine?

Wrong. The usual HTML snippet for exploiting CSRF here looks like this (example.com is your Drupal site):

<img src="http://example.com/mymodule/pants/1337/delete">

Chain of an attack

  • The attacker posts a comment on your site: "Look what a nice picture I found" and the image snippet from above.
  • You are logged in as admin and you see that there is a new comment, so you go to that comment page.
  • Your browser renders the content, sees the image and tries to fetch it.
  • Your browser sends the cookies along, so permission is granted to the page callback (you as admin are allowed to delete pants).
  • The delete query is executed and pants with ID 1337 are removed.
  • Your browser receives an HTML response from Drupal and cannot display it. It will show a broken image or similar.
  • You think: "What a dumb comment, the image does not even work, LOL!"
  • Later you realize that somehow the 1337 pants are gone, but you have no idea why.

The attacker does not even have to post the malicious HTML snippet on your site, she can also post it on her own site, or to Facebook for example. She only needs you to load the image or follow the link, and all your pants are in danger.

Solution

There are two common strategies to solve this problem:

  • Confirmation form: the action is not performed immediately and the user has to press an extra button in order to proceed with deleting pants.
  • Security Tokens: the menu link has an additional security token in its path that is validated before executing the action. drupal_get_token() and drupal_valid_token() can generate/validate the tokens for you and when the link is displayed the token is added. An attacker cannot know your token, so the validation will fail and access will be denied in that case.

A typical use case for such action links that have to be protected is implemented in the Rules Link module that we heavily use for our Recruiter and jobiqo products. I would recommend to look at its hook_menu() implementations and access/page callbacks for examples for confirmation forms and token protection. There is also an interesting Drupal Scout article about how to protect your Drupal site against CSRF.

More advanced POST cases

I will follow-up with CSRF examples for POST requests in a future blog post. Stay tuned!

Comments

Thanks, excellent explanation ! I'm looking forward for the next one :-)

Very useful resource Klaus!
I think this is d.o docs material :)

This sandbox is somehow useful for this topic http://drupal.org/sandbox/davereid/1332490

Wow fantastic explanation. Especially the example! <img src="just kiding :)">

Great discussion of CRSF, and both approaches - a confirmation form, and a security token - are valid security tools. From a HTTP proper practice perspective, GET requests should not alter the data on the server; content-changes should only be submitted by POST requests (or PUT, etc, if you get into the realms of full REST APIs). GET requests should never change content, so therefore confirmation-forms are the way forward for this kind of practice.

The confirm_form() API is a useful shortcut for building confirmation forms.

Now I pretty new to programming and all that stuff, but I think it is really scary how some people are capable of coding like this... At least I can begin to understand the workings with this kind of article

There's a more general page at http://www.drupalscout.com/tags/csrf that includes an intro to CSRF video.

Thank you, this post was really helpful for me and opened my eyes on a security problem we are not always aware of

Its very simple and clear explanation for the CSRF vulnerabilities.

Feedback