wikiHow to Prevent Cross Site Request Forgery (CSRF) Attacks in PHP

Three Methods:Overview of MethodsCreate csrf.class.php FileProtecting Pages With csrf.class.php

A Cross Site Request Forgery (CSRF) Attack is a type of web application vulnerability where the victim unintentionally runs a script in their browser that takes advantage of their logged in session to a particular site. CSRF attacks can be performed over GET or POST requests. This article will show you how to help prevent CSRF attacks on your web application.

Method 1
Overview of Methods

We will use two methods to help prevent CSRF attacks on your GET and POST requests.


The first it to include a random token with each request, this is a unique string that is generated for each session. We generate the token and then include it in every form as a hidden input. The system then checks if the form is valid by comparing the token with the one stored in the users session variable. This means that in order or an attacker to generate a request, the attacker would have to know the token value.


The second method is to use random name for each form field. The value of the random name for each field is stored in a session variable and after the form has been submitted the system generates a new random value. This means in order for an attack to work the attacker would have to guess these random form names.


For example a request that once looked like this:

Image titled Passwordscsrf.png

Will now look like this:

Image titled Protectedrequestcsrf.png

Method 2
Create csrf.class.php File

This is the main file that will contain all the functions in that will be used to prevent CSRF attacks.

  1. Image titled 2543022 1 2
    1
    Create csrf.class.php. Start off by create the file and saving it with the content below:

     <?php class csrf { 
    All code in this section of the guide will be added to the end of this file.
  2. Image titled 2543022 2 2
    2
    Create get_token_id() Function.
    This function get the token id from the users session, if one has not already been created then it generates a random token.

     public function get_token_id() { if(isset($_SESSION['token_id'])) { return $_SESSION['token_id']; } else { $token_id = $this->random(10); $_SESSION['token_id'] = $token_id; return $token_id; } } 
  3. Image titled 2543022 3 2
    3
    Create get_token() Function.
    This function gets the token value, if one has not already been generated then it generates one.

     public function get_token() { if(isset($_SESSION['token_value'])) { return $_SESSION['token_value']; } else { $token = hash('sha256', $this->random(500)); $_SESSION['token_value'] = $token; return $token; } } 
  4. Image titled 2543022 4 2
    4
    Create check_valid() Function.
    This function is used to check if the token id and the token value are valid. It does this by checking the values of the GET or POST request with the values stored in the users SESSION variable.

     public function check_valid($method) { if($method == 'post' || $method == 'get') { $post = $_POST; $get = $_GET; if(isset(${$method}[$this->get_token_id()]) && (${$method}[$this->get_token_id()] == $this->get_token())) { return true; } else { return false; } } else { return false; } } 


  5. Image titled 2543022 5 2
    5
    Create form_names() Function.
    This is the second defense against CSRF in this article. This function generates random names for the form fields.

     public function form_names($names, $regenerate) { $values = array(); foreach ($names as $n) { if($regenerate == true) { unset($_SESSION[$n]); } $s = isset($_SESSION[$n]) ? $_SESSION[$n] : $this->random(10); $_SESSION[$n] = $s; $values[$n] = $s; } return $values; } 


  6. Image titled 2543022 6 2
    6
    Create the random() Function.
    This function generates a random string using the linux random file for more entropy.

     private function random($len) { if (function_exists('openssl_random_pseudo_bytes')) { $byteLen = intval(($len / 2) + 1); $return = substr(bin2hex(openssl_random_pseudo_bytes($byteLen)), 0, $len); } elseif (@is_readable('/dev/urandom')) { $f=fopen('/dev/urandom', 'r'); $urandom=fread($f, $len); fclose($f); $return = ''; } if (empty($return)) { for ($i=0;$i<$len;++$i) { if (!isset($urandom)) { if ($i%2==0) { mt_srand(time()%2147 * 1000000 + (double)microtime() * 1000000); } $rand=48+mt_rand()%64; } else { $rand=48+ord($urandom[$i])%64; } if ($rand>57) $rand+=7; if ($rand>90) $rand+=6; if ($rand==123) $rand=52; if ($rand==124) $rand=53; $return.=chr($rand); } } return $return; } 
  7. Image titled 2543022 7 2
    7
    Close the Class Bracket.
    This will end the class csrf.

     } 
    You can now close the file csrf.class.php as we have finished editing it.

Method 3
Protecting Pages With csrf.class.php

These steps will show you how to use the CSRF class to prevent CSRF attacks.

  1. Image titled 2543022 8 2
    1
    Protecting a POST Form.
    The code below shows how to implement the csrf class on a form.

     <?php session_start(); include 'csrf.class.php'; $csrf = new csrf(); // Generate Token Id and Valid $token_id = $csrf->get_token_id(); $token_value = $csrf->get_token($token_id); // Generate Random Form Names $form_names = $csrf->form_names(array('user', 'password'), false); if(isset($_POST[$form_names['user']], $_POST[$form_names['password']])) { // Check if token id and token value are valid. if($csrf->check_valid('post')) { // Get the Form Variables. $user = $_POST[$form_names['user']]; $password = $_POST[$form_names['password']]; // Form Function Goes Here } // Regenerate a new random value for the form. $form_names = $csrf->form_names(array('user', 'password'), true); } ?> <form action="index.php" method="post"> <input type="hidden" name="<?= $token_id; ?>" value="<?= $token_value; ?>" /> <input type="text" name="<?= $form_names['user']; ?>" /><br/> <input type="text" name="<?= $form_names['password']; ?>" /> <input type="submit" value="Login"/> </form> 




Article Info

Categories: Web Programming | PHP