PHP Security: Nonce or Unique Form Key Issue

I use this class (taken from the blog tutorial) to generate unique keys for validating the form:

class formKey {
    //Here we store the generated form key
    private $formKey;

    //Here we store the old form key
    private $old_formKey;

    //The constructor stores the form key (if one excists) in our class variable
    function __construct() {
        //We need the previous key so we store it
        if(isset($_SESSION['form_key'])) {
            $this->old_formKey = $_SESSION['form_key'];
        }
    }

    //Function to generate the form key
    private function generateKey() {
        //Get the IP-address of the user
        $ip = $_SERVER['REMOTE_ADDR'];

        //We use mt_rand() instead of rand() because it is better for generating random numbers.
        //We use 'true' to get a longer string.
        $uniqid = uniqid(mt_rand(), true);

        //Return the hash
        return md5($ip . $uniqid);
    }

    //Function to output the form key
    public function outputKey() {
        //Generate the key and store it inside the class
        $this->formKey = $this->generateKey();
        //Store the form key in the session
        $_SESSION['form_key'] = $this->formKey;

        //Output the form key
        // echo "<input type='hidden' name='form_key' id='form_key' value='".$this->formKey."' />";
        return $this->formKey;
    }

    //Function that validated the form key POST data
    public function validate() {
        //We use the old formKey and not the new generated version
        if($_POST['form_key'] == $this->old_formKey) {
            //The key is valid, return true.
            return true;
        }
        else {
            //The key is invalid, return false.
            return false;
        }
    }
}

Everything on my site first goes through index.php, so I put this in index.php: $formKey = new formKey();

Then in each form I put this: <?php $formKey->outputKey();?> <?php $formKey->outputKey();?>

This generates this: <input type="hidden" name="form_key" id="form_key" value="7bd8496ea1518e1850c24cf2de8ded23"/>

Then I can just check if(!isset($_POST['form_key']) || !$formKey->validate())

I have two problems. First: I cannot use more than one form per page, because only the last generated key will be checked.

Second: since everything goes through index.php first, if I use ajax to validate the form, the first time it will be checked, and the second not, because index.php generates a new key, but the pages containing the form are not updated, so the form key not updated..

, .. , / /​​, ?? !!!

+3
2

, . , .

//Put this in a header file
session_start();
if(!$_SESSION['xsrf_token']){
     //Not the best but this should be enough entropy
     $_SESSION['xsrf_token']=uniqid(mt_rand(),true);
}    
//$_REQUEST is used because you might need it for a GET or POST request. 
function validate_xsrf(){
   return $_SESSION['xsrf_token']==$_REQUEST['xsrf_token'] && $_SESSION['xsrf_token'];
}
//End of header file. 

&& $_SESSION['xsrf_token'] . , , . (, doah!;)

html/php , XSRF, , .

if(validate_xsrf()){
   //do somthing with $_POST
}

, , , , session_start();, - , , .

<input type="hidden" name="xsrf_token" id="form_key" value="<?=$_SESSION['xsrf_token']?>" />
+3

, .

class formKey {
    //Here we store the generated form key
    private $formKey;

    //Here we store the old form key
    private $old_formKey;

    //The constructor stores the form key (if one excists) in our class variable
    function __construct() {
        //We need the previous key so we store it
        if(isset($_SESSION['form_key'])) {
            $this->old_formKey = $_SESSION['form_key'];
            $this->formKey = $this->generateKey();
            $_SESSION['form_key'] = $this->formKey;
        }
    }

    //Function to generate the form key
    private function generateKey() {
        //Get the IP-address of the user
        $ip = $_SERVER['REMOTE_ADDR'];

        //We use mt_rand() instead of rand() because it is better for generating random numbers.
        //We use 'true' to get a longer string.
        $uniqid = uniqid(mt_rand(), true);

        //Return the hash
        return md5($ip . $uniqid);
    }

    //Function to output the form key
    public function outputKey() {
        return $this->formKey;
    }

    //Function that validated the form key POST data
    public function validate() {
        //We use the old formKey and not the new generated version
        if($_POST['form_key'] == $this->old_formKey) {
            //The key is valid, return true.
            return true;
        }
        else {
            //The key is invalid, return false.
            return false;
        }
    }
}

: . outputkey(), . .

+2

Source: https://habr.com/ru/post/1753230/


All Articles