Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for How To Create A Simple Nonce in PHP
Simon Ugorji
Simon Ugorji

Posted on

     

How To Create A Simple Nonce in PHP

A Nonce is anumber or a token used only once.

You can use Nonce in your pages or forms to add an extra layer of security to your App and one of its features is todifferentiate humans from bots.

Today, I will show you how to create a simple Nonce in PHP, and how you can validate it.

LET'S BEGIN

First, we will create aclass that will haveprivate and public methods that will generate and validate our Nonce based on the secret hash which we will define.

OUR CLASS

session_start();define('NONCE_SECRET','CEIUHET745T$^&%&%^gFGBF$^');classNonce{/**     * Generate a Nonce.      *      * The generated string contains four tokens, separated by a colon.     * The first part is the salt.      * The second part is the form id.     * The third part is the time until the nonce is invalid.     * The fourth part is a hash of the three tokens above.     *      * @param $length: Required (Integer). The length of characters to generate     * for the salt.     *      * @param $form_id: Required (String). form identifier.     *      * @param $expiry_time: Required (Integer). The time in minutes until the nonce      * becomes invalid.      *      * @return string the generated Nonce.     *     *//**     * Verify a Nonce.      *      * This method validates a nonce     *     * @param $nonce: Required (String). This is passed into the verifyNonce     * method to validate the nonce.     *       * @return boolean: Check whether or not a nonce is valid.     *      */}
Enter fullscreen modeExit fullscreen mode

Now we need to set up aprivate function (method) that will generate random characters which is oursalt, up to the characters that we will specify in itslength parameter.

Let us make this method a public function, as we test run our code.

publicfunctiongenerateSalt($length=10){//set up random characters$chars='1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';//get the length of the random characters$char_len=strlen($chars)-1;//store output$output='';//iterate over $charswhile(strlen($output)<$length){/* get random characters and append to output                till the length of the output is greater than the length provided */$output.=$chars[rand(0,$char_len)];}//return the resultreturn$output;}
Enter fullscreen modeExit fullscreen mode

Here's the full code

session_start();define('NONCE_SECRET','CEIUHET745T$^&%&%^gFGBF$^');classNonce{publicfunctiongenerateSalt($length=10){//set up random characters$chars='1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';//get the length of the random characters$char_len=strlen($chars)-1;//store output$output='';//iterate over $charswhile(strlen($output)<$length){/* get random characters and append to output till the length of the output              is greater than the length provided */$output.=$chars[rand(0,$char_len)];}//return the resultreturn$output;}}
Enter fullscreen modeExit fullscreen mode

Let us use the new keyword to create an instance of the class, and invoke thegenerateSalt() method.

$nonce=newNonce();var_dump($nonce->generateSalt(22));
Enter fullscreen modeExit fullscreen mode

This is our result, notice that the random characters were generated up to the length we specified.

nonce

Now we need another private method that will take advantage of $_SESSION, to store the generated Nonces using the form ID.

privatefunctionstoreNonce($form_id,$nonce){//Argument must be a stringif(is_string($form_id)==false){thrownewInvalidArgumentException("A valid Form ID is required");}//group Generated Nonces and store with md5 Hash$_SESSION['nonce'][$form_id]=md5($nonce);returntrue;}
Enter fullscreen modeExit fullscreen mode

Next, we need to create another method that willhash our salt, our secret, and a specific time of expiry as tokens. Then we will generate a nonce by separating each token with a colon and store it in a session variable using thestoreNonce method.

publicfunctiongenerateNonce($length=10,$form_id,$expiry_time){//our secret$secret=NONCE_SECRET;//secret must be valid. You can add your regExp hereif(is_string($secret)==false||strlen($secret)<10){thrownewInvalidArgumentException("A valid Nonce Secret is required");}//generate our salt$salt=self::generateSalt($length);//convert the time to seconds$time=time()+(60*intval($expiry_time));//concatenate tokens to hash$toHash=$secret.$salt.$time;//send this to the user with the hashed tokens$nonce=$salt.':'.$form_id.':'.$time.':'.hash('sha256',$toHash);//store Nonceself::storeNonce($form_id,$nonce);//return noncereturn$nonce;}
Enter fullscreen modeExit fullscreen mode

Here's the full code

session_start();define('NONCE_SECRET','CEIUHET745T$^&%&%^gFGBF$^');classNonce{//generate saltpublicfunctiongenerateSalt($length=10){//set up random characters$chars='1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';//get the length of the random characters$char_len=strlen($chars)-1;//store output$output='';//iterate over $charswhile(strlen($output)<$length){/* get random characters and append to output till the length of the output              is greater than the length provided */$output.=$chars[rand(0,$char_len)];}//return the resultreturn$output;}//store NonceprivatefunctionstoreNonce($form_id,$nonce){//Argument must be a stringif(is_string($form_id)==false){thrownewInvalidArgumentException("A valid Form ID is required");}//group Generated Nonces and store with md5 Hash$_SESSION['nonce'][$form_id]=md5($nonce);returntrue;}//hash tokens and return noncepublicfunctiongenerateNonce($length=10,$form_id,$expiry_time){//our secret$secret=NONCE_SECRET;//secret must be valid. You can add your regExp hereif(is_string($secret)==false||strlen($secret)<10){thrownewInvalidArgumentException("A valid Nonce Secret is required");}//generate our salt$salt=self::generateSalt($length);//convert the time to seconds$time=time()+(60*intval($expiry_time));//concatenate tokens to hash$toHash=$secret.$salt.$time;//send this to the user with the hashed tokens$nonce=$salt.':'.$form_id.':'.$time.':'.hash('sha256',$toHash);//store Nonceself::storeNonce($form_id,$nonce);//return noncereturn$nonce;}}
Enter fullscreen modeExit fullscreen mode

So let us invoke the methodgenerateNonce(), and pass in5 as the first argument (this will be used to generate our salt),form_login as the second argument (this will be the form we wish to use the nonce on), and10 as the third or last argument (this will be how long our nonce will last for in minutes).

$nonce=generateNonce();var_dump($nonce->generateNonce(5,"form_login",10));var_dump($_SESSION);
Enter fullscreen modeExit fullscreen mode

Here's our nonce and its stored value in the session.

nonce

You can see that we have each token separated by a colon in the generated nonce, and we have it stored in the session by hashing it with** md5()**.

Now we need to code a public method that will verify a nonce and return a boolean (true or false), depending on whether or not the nonce is valid.

Before we code this method, you need to understand that:

  • Our nonce is stored in $_SESSION
  • Our tokens are separated by a colon ($salt : $form_id : $time : $hash)
  • We will use the same secret used to generate the Nonce, to verify it.
publicfunctionverifyNonce($nonce){//our secret$secret=NONCE_SECRET;//split the nonce using our delimeter : and check if the count equals 4$split=explode(':',$nonce);if(count($split)!==4){returnfalse;}//reassign variables$salt=$split[0];$form_id=$split[1];$time=intval($split[2]);$oldHash=$split[3];//check if the time has expiredif(time()>$time){returnfalse;}/* Nonce is proving to be valid, continue ... *///check if nonce is present in the sessionif(isset($_SESSION['nonce'][$form_id])){//check if hashed value matchesif($_SESSION['nonce'][$form_id]!==md5($nonce)){returnfalse;}}else{returnfalse;}//check if the nonce is valid by rehashing and matching it with the $oldHash$toHash=$secret.$salt.$time;$reHashed=hash('sha256',$toHash);//match with the tokenif($reHashed!==$oldHash){returnfalse;}/* Wonderful, Nonce has proven to be valid*/returntrue;}
Enter fullscreen modeExit fullscreen mode

So we have a few conditions in the method above that checks the nonce. This method will only returntrue when the checks are successful andfalse when one or more checks fail.

Here are the checks:

  • If the tokens are not complete, the nonce is invalid
  • If Nonce is not stored in the session, the Nonce is invalid
  • If Nonce is stored but the value does not match, the Nonce is invalid
  • If the time has elapsed, the nonce is invalid
  • If there's an alteration to the hash, the nonce is invalid

Let us create a nonce and verify it to confirm if our class works and we can replace thepublic function generateSalt() with aprivate function so that it can only be accessed within our class.

Here's the full code

session_start();define('NONCE_SECRET','CEIUHET745T$^&%&%^gFGBF$^');classNonce{//generate saltprivatefunctiongenerateSalt($length=10){//set up random characters$chars='1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';//get the length of the random characters$char_len=strlen($chars)-1;//store output$output='';//iterate over $charswhile(strlen($output)<$length){/* get random characters and append to output till the length of the output              is greater than the length provided */$output.=$chars[rand(0,$char_len)];}//return the resultreturn$output;}//store NonceprivatefunctionstoreNonce($form_id,$nonce){//Argument must be a stringif(is_string($form_id)==false){thrownewInvalidArgumentException("A valid Form ID is required");}//group Generated Nonces and store with md5 Hash$_SESSION['nonce'][$form_id]=md5($nonce);returntrue;}//hash tokens and return noncepublicfunctiongenerateNonce($length=10,$form_id,$expiry_time){//our secret$secret=NONCE_SECRET;//secret must be valid. You can add your regExp hereif(is_string($secret)==false||strlen($secret)<10){thrownewInvalidArgumentException("A valid Nonce Secret is required");}//generate our salt$salt=self::generateSalt($length);//convert the time to seconds$time=time()+(60*intval($expiry_time));//concatenate tokens to hash$toHash=$secret.$salt.$time;//send this to the user with the hashed tokens$nonce=$salt.':'.$form_id.':'.$time.':'.hash('sha256',$toHash);//store Nonceself::storeNonce($form_id,$nonce);//return noncereturn$nonce;}publicfunctionverifyNonce($nonce){//our secret$secret=NONCE_SECRET;//split the nonce using our delimeter : and check if the count equals 4$split=explode(':',$nonce);if(count($split)!==4){returnfalse;}//reassign variables$salt=$split[0];$form_id=$split[1];$time=intval($split[2]);$oldHash=$split[3];//check if the time has expiredif(time()>$time){returnfalse;}/* Nonce is proving to be valid, continue ... *///check if nonce is present in the sessionif(isset($_SESSION['nonce'][$form_id])){//check if hashed value matchesif($_SESSION['nonce'][$form_id]!==md5($nonce)){returnfalse;}}else{returnfalse;}//check if the nonce is valid by rehashing and matching it with the $oldHash$toHash=$secret.$salt.$time;$reHashed=hash('sha256',$toHash);//match with the tokenif($reHashed!==$oldHash){returnfalse;}/* Wonderful, Nonce has proven to be valid*/returntrue;}}
Enter fullscreen modeExit fullscreen mode

So I generated a nonce and passed it as a string to the method and it worked perfectly!

To verify your nonces, note that Iftrue is returned, it means that the nonce is still valid, but Iffalse is returned, it means that the nonce is invalid.

So our function works perfectly! In order to use this nonce, you need to place the class into a file and include that file into your page using therequire() keyword.

Then create a new instance of the class, and generate a nonce

//include noncerequire_once('nonce.php');//create new instance of the class$nonce=newNonce();//generate nonce$myToken=$nonce->generateNonce(25,'form_login',10);//verify nonce$result=$nonce->verifyNonce($myToken)//display resultvar_dump($result);
Enter fullscreen modeExit fullscreen mode

So there you have it

nonce


AMAZING ISN'T IT?

spongeBob

Make it suit your project by using a very strong secret.

You have reached the end of my article.

EXTRA

I recently launched a JavaScript package that validates your HTML forms using validation rules, regular expressions, and form input attributes.

I will appreciate it if you spared a few seconds to check it out.

octaValidate - A client-side form validation library | Product Hunt

This Tiny Script helps to validate your HTML forms using validation rules, sophisticated regular expressions and form input attributes.

favicon producthunt.com

Thank You

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Backend Developer, Technical Writer ¦ PHP ¦ JavaScript
  • Location
    Nigeria
  • Joined

More fromSimon Ugorji

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp