Create forms in a safe way to avoid cross-site request forgeries (CSRF)
Cross-site request forgery (CSRF or XSRF) is a process where a request is made to a site which takes an action when the user did not intend to take that action. This can be achieved in a variety of ways, but in Drupal it is simple to protect against this type of attack.
The HTTP 1.1 specification makes a clear distinction that POST requests can modify data in the site (section 9.5) while GET requests should not modify data (section 9.3). Modules that modify data should require a POST request (i.e. a form).
In versions of Drupal prior to the release of SA-2007-017 it was possible to create a specifically formed page that contained image tags where the image "src" element was a link to certain menu "disable" URLs on a Drupal site. If a site admin visited that page when they were logged into their site then their browser would request the URL of the menu disable page which would then disable their menu items.
Protecting against CSRF in Drupal
The Drupal Form API provides protection against CSRF using special tokens in the forms which are added automatically. If your module uses the Form API for all requests that modify data and if you properly follow the Form API documentation then your module is protected from CSRF.
Bad code could take two forms:
- Using the $_POST variables directly and creating a form via HTML instead of the Drupal Form API
- Using a link and a menu callback to handle a action that modifies data (especially destructive modifications like deletion)
You can see the Drupal Core CSRF vulnerabilities fixed in 5.2 for an example of "bad code" and how to fix it.
See the Forms API documentation.
If you've discovered that you have menu callbacks that are vulnerable to CSRF, the simplest solution may be to add a confirmation form via confirm_form() for each of your menu callbacks. Drupal does most of the work for you. See for example:
Alternatively, you can use drupal_get_token() and drupal_valid_token() to generate a token that can be used with regular links. However, this is generally discouraged, and should never be used when the link's resulting action would modify data. For an example usage of drupal_get_token, see: