How to Prevent Cross Site Request Forgery in PHP

From WikiHTP

Cross-Site Request Forgery or CSRF can force an end user to unknowingly generate malicious requests to a web server. This attack vector can be exploited in both POST and GET requests. Let's say for example the URL endpoint /delete.php?accnt=12 deletes account as passed from accnt parameter of a GET request. Now if an authenticated user will encounter the following script in any other application

<img src="http://domain.com/delete.php?accnt=12" width="0" height="0" border="0">

the account would be deleted. So here we are about to discuss how to prevent Cross-Site Request Forgery in PHP.

Use CSRF Tokens[edit]

A common solution to this problem is the use of CSRF tokens. CSRF tokens are embedded into requests so that a web application can trust that a request came from an expected source as part of the application's normal workflow. First, the user performs some action, such as viewing a form, that triggers the creation of a unique token. A sample form implementing this might look like

<form method="get" action="/delete.php">
  <input type="text" name="accnt" placeholder="accnt number" />
  <input type="hidden" name="csrf_token" value="<randomToken>" />
  <input type="submit" />
</form>

The token can then be validated by the server against the user session after form submission to eliminate malicious requests.

Sample Code for a Basic Implementation[edit]

Here is sample code for a basic implementation:

/* Code to generate a CSRF token and store the same */
...
<?php
  session_start();
  function generate_token() {
    // Check if a token is present for the current session
    if(!isset($_SESSION["csrf_token"])) {
        // No token present, generate a new one
        $token = random_bytes(64);
        $_SESSION["csrf_token"] = $token;
    } else {
        // Reuse the token
        $token = $_SESSION["csrf_token"];
    }
    return $token;
  }
?>
<body>
  <form method="get" action="/delete.php">
    <input type="text" name="accnt" placeholder="accnt number" />
    <input type="hidden" name="csrf_token" value="<?php echo generate_token();?>" />
    <input type="submit" />
  </form>
</body>
...


/* Code to validate token and drop malicious requests */
...
<?php
  session_start();
  if ($_GET["csrf_token"] != $_SESSION["csrf_token"]) {
    // Reset token
    unset($_SESSION["csrf_token"]);
    die("CSRF token validation failed");
  }
?>
...

There are many libraries and frameworks already available which have their own implementation of CSRF validation. Though this is the simple implementation of CSRF, You need to write some code to regenerate your CSRF token dynamically to prevent from CSRF token stealing and fixation.

About This Tutorial

This page was last edited on 28 January 2019, at 07:36.