Nathan Bateman
Nathan Bateman

Reputation: 1

PHP Session Tokens for form security

I have not been able to successfully submit a form I am working on in Chrome or Firefox. The form works in Safari, however.

I just started trying to use PHP last week and modified code from this post on CSS Tricks. I am trying to give the session a random token, store that token in a variable, set that token to a hidden input field, and then make sure the two match when the form is submitted.

The problem is that the session token that is created doesn't match the token assigned as a value to the hidden input. When the form is submitted, a new session token is recreated and thus doesn't match the original random number from the session. The curious thing is that it works in Safari and not other browsers.

The PHP

<?php 
session_start();

function generateFormToken($form) {

    // generate a token from an unique value, took from microtime, you can also use salt-values, other crypting methods...
    $token = md5(uniqid(microtime(), true));  

    // Write the generated token to the session variable to check it against the hidden field when the form is sent
    $_SESSION[$form.'_token'] = $token; 
    echo $token;
    return $token;
}

function verifyFormToken($form) {

    // check if a session is started and a token is transmitted, if not return an error
    if(!isset($_SESSION[$form.'_token'])) { 
        return false;
    }

    // check if the form is sent with token in it
    if(!isset($_POST['token'])) {
        return false;
    }

    // compare the tokens against each other if they are still the same
    if ($_SESSION[$form.'_token'] !== $_POST['token']) {
        return false;
    }

    return true;
}
function check_input($data)
{
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
  }

if (verifyFormToken('form1')) {
    $name = check_input($_POST["name"]);
    $email = check_input($_POST["emailaddress"]);
    $message = check_input($_POST["message"]);
    $ForwardTo = '[email protected]';
    $details='Name: '.$name."\n".'Email: '.$email."\n".'Message: '.$message."\n";

        //do stuff
    mail($ForwardTo,"Construction of Hope Contact",$details,"From:$email");
}

?>

The related form:

<!--Markup for Contact form-->
		<form action='index.php' method='post' class='contact-format'>


		<p><input type="hidden" name="token" value="<?php echo $newToken; ?>"></p>
		<p>
      <button type="submit" name='submit' class="btn btn-primary button">Send</button>
    </p>

Upvotes: 0

Views: 15003

Answers (2)

Nathan Bateman
Nathan Bateman

Reputation: 1

The functionality of my code seemed fine in Safari, but other browsers mismatched the token.

The issue involved .... not having a favicon.

This post was the key in solving the problem.

Upvotes: 0

Rasclatt
Rasclatt

Reputation: 12505

I think what you have is pretty close. I think I would change a couple of things, but overall I think what you have is close:

/functions/validate.php

function fetchToken($form)
    {
        $token  =   md5(uniqid(microtime(), true));
        $_SESSION['token'][$form]   =   $token; 
        // Just return it, don't echo and return
        return $token;
    }

function matchToken($form)
    {
        if(!isset($_POST['token'][$form]))
            return false;
        // I would clear the token after matched
        if($_POST['token'][$form] === $_SESSION['token'][$form]) {
            $_SESSION['token'][$form]   =   NULL;
            return true;
        }
        // I would return false by default, not true
        return false;
    }

index.php

// Include functions
include(__DIR__.'/functions/validate.php');
// Start session
session_start();
// match the token
if(matchToken('mailer')) {
    // do stuff
    echo true;
}
?>
<form action='index.php' method='post' class='contact-format'>
    <!-- You will echo here and also set the session variable here -->
    <!-- I would also use an array to contain my tokens, cleaner I think -->
    <input type="hidden" name="token[mailer]" value="<?php echo fetchToken('mailer'); ?>">
    <button type="submit" name='submit' class="btn btn-primary button">Send</button>
</form>

Upvotes: 1

Related Questions