Jump to content

How to check token in form created by password_hash() function


Go to solution Solved by requinix,

Recommended Posts

Hi, i'm making a contact form with hidden field that will create token and store it in session so i can prevent form spaming and other things.

 

But i'm facing problem because i don't know how to check token from session with password_verify() function.

<?php
error_reporting(E_ALL);
session_start();

function create_token()
{
	$_SESSION['token'] = password_hash(mt_rand(5,99), PASSWORD_DEFAULT);
	return $_SESSION['token'];
}

function validate_token($token)
{
	if (isset($_SESSION['token']) && !empty($_SESSION['token'])) {
		$token = $_SESSION['token'];
		if (password_verify($token, $_SESSION['token'])) {
			return true;
		}
	} else {
		return false;
	}
}

function delete_token($token)
{
	if (isset($_SESSION['token']) && !empty($_SESSION['token'])) {
		session_destroy($_SESSION['token']);
		$_SESSION['token'] = '';
		return true;
	}
}

if (isset($_POST['submit'])) {
	$name = $_POST['name'];
	$email = $_POST['email'];
	$subject = $_POST['subject'];
	$message = $_POST['message'];
	$token = $_POST['token'];

	if (validate_token($token) === true) {
		echo "valid token";
		delete_token($token);
	} else {
		echo "invalid token";
	}
}

?>

<!DOCTYPE html>
<html>
<head>
	<title>Contact form</title>

<style type="text/css">
	body {
		background-color: #f1f1f1;
	}
	form {
		font-family: Tahoma, Arial, sans-serif;
		font-size: 12px;
		border: 1px solid #e2e2e2;
		width: 286px;
		margin: 0 auto;
		padding: 20px;
		background-color: #fff;
	}

	label {
		display: block;
		padding: 0 0 5px 0;
		font-weight: bold;
	}

	input, textarea {
		padding: 4px;
		width: 285px;
		margin: 0 0 10px 0;
		border: 1px solid #e2e2e2;
		font-size: 12px;
		background-color:#f7f7f7;
	}

	input:focus, textarea:focus {
		border:1px solid steelblue;
	}

	textarea {
		min-height: 100px;
		height: 100px;
	}

	input[type="submit"] {
		width: 286px;
	    padding: 10px;
	    color: #fff;
	    background-color: steelblue;
	    border: none;
	}

	.required {
		font-weight: bolder;
		color: red;
	}
</style>

</head>
<body>

<form action="" method="POST">
	<h2>Contact us</h2>
	<p>All fields marked with an  <span class="required">*</span> are required</p>
	<label for="name">Name <span class="required">*</span></label>
	<input type="text" name="name" id="name"><br />
	<label for="email">Email <span class="required">*</span></label>
	<input type="email" name="email" id="email"><br />
	<label for="subject">Subject <span class="required">*</span></label>
	<input type="text" name="subject" id="subject"><br />
	<label for="message">Message <span class="required">*</span></label>
	<textarea name="message" id="message"></textarea><br />
	<input type="hidden" name="token" value="<?php echo create_token(); ?>">
	<input type="submit" name="submit" value="Submit">
</form>

</body>
</html>
  • Solution

Is this token a password? No? Then don't try to make it a password. All you need is a random value, so

sha1(uniqid(time(), true))
is sufficient.

 

Put the value in the form and in the session, then compare the two values. Regular string comparison.

I'm sure Jacques can find all sorts of reasons why what I posted is horrible.

 

This token doesn't have to be globally unique. It's far more likely that someone would bypass the token mechanism itself than collisions becoming an issue.

Can't it just be any random value?

Pretty much. uniqid+time to get a unique-ish value, then sha1 to make it look random (check the actual value of uniqid+time sometime) as well as definitely HTML safe (the output being only letters and numbers).

 

Such as "axbacx" or a RAND function value? It just has to be a value that you can store in the session and hidden on the form and nothing terribly unique.

"axbacx" is random, but the point here is an unpredictable random value. So something static won't work ;)

 

RAND/rand/mt_rand is just a random number, which is fine, except it's short and unintimidating. A little more effort would be nice.

If that is the way you are going to do it, I would suggest two functions (saved in one module). One function to create the token value and to save it in the session and return it to the caller for use in the form. The other function to do the validation of the token upon the return of the form.

 

That way should you want to alter anything you only need to modify the two functions and not have to worry about all the places you used them.

Guys, it's 2017. Even PHP has a proper randomness API now (as well as a polyfill for the users of PHP 5).

 

The days where you could use kindergarten functions like this SHA-1 stuff without getting laughed at are over.

<?php

// include the random_compat library if you don't have PHP 7 yet

const TOKEN_BYTE_COUNT = 16;



function generate_token()
{
    return bin2hex(random_bytes(TOKEN_BYTE_COUNT));
}
Edited by Jacques1
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.