PHP Session Tokens for form security - php

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 = 'me#gmail.com';
$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>

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>

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.

Related

PHP class, html forum, print $_POST Array on page

i am beginner php programmer, iv been trying to create a small program that takes input from a forum and then after submission i want it to be printed on the screen. simple and easy i thought, iv been trying and suspiciously it seems to work fine for 1 text field, when i added the remaining 2 text fields called [fam][user] my code stops returning the content to the screen. also i started to recieve an error of an unindex array, therefore i had to use isset to counter this problem, and also, why does my code call the destructor although i never implicitly set my destructor. i dont know how to ask these questions because the errors arent consistent.
code doesnt print my [name][fam][user]
code prints [name] when everything about [fam][user] are ommited from the code.
-code sometimes called the destructor
-code doesnt clear html previous input(e.g, when working with the one text field, lets say i input the [name] john, and click submit it
displays submit, then,i refresh the page, and the name john is still
displayed, why doesnt the destructor clear the memory of name from my
submission.
<form class="nameform" action="book.php" method="post">
<input type="text" name="Name" value="1">
<input type="text" name="Fam" value="2">
<input type="text" name="User" value="3">
<input type="button" name="submit" value="Submit">
</form>
private $name; private $familyName; private $userName;
function __construct($names,$familyNames,$userNames)
{
$this->name = $names;
$this->familyName = $familyNames;
$this->userName = $userNames;
}
function getName()
{
return $this->name;
}
function getFamilyName()
{
return $this->familyName;
}
function getUserName()
{
return $this->userName;
}
public function __destruct()
{
echo "destroyed again";
$this->name;
$this->familyName;
$this->userName;
}
}
if(!isset( $_POST["Name"])||!isset($_POST["Fam"])||!isset($_POST["User"]))
{
echo "Please fill in the data";
} else {
$p1 = new Person($_POST["Name"],$_POST["Fam"],$_POST["User"]);
print $p1->getName();
print $p1->getFamilyName();
print $p1->getUserName();
print_r($_POST);
}
// $n = $_POST["Name"];
// $f = $_POST["Fam"];
// $u = $_POST["User"];
// $p1 = new Person($_POST["Name"],$_POST["Fam"],$_POST["User"]);
?>
code doesnt print my [name][fam][user]
You never echo them out of the destuctor
public function __destruct()
{
echo "destroyed again";
$this->name; //<---- does nothing
$this->familyName;
$this->userName;
}
So I am not sure what this is supposed to do. You have them down at the bottom
print $p1->getName();
print $p1->getFamilyName();
print $p1->getUserName();
But the only thing you'll get from the destruct method is
"destroyed again"
And you will only see that if everything in the form is set. Which it always is when the form is submitted, because type text is always submitted with its form.
Which brings me to this, you should be checking empty instead of isset there
if ('POST' === $_SERVER['REQUEST_METHOD']) { //check if POST
if(empty($_POST["Name"])||empty($_POST["Fam"])||empty($_POST["User"])){
echo "Please fill in the data";
} else {
$p1 = new Person($_POST["Name"],$_POST["Fam"],$_POST["User"]);
print $p1->getName();
print $p1->getFamilyName();
print $p1->getUserName();
print_r($_POST);
}
}
Note that anything falsy will be empty, false, [], '', 0, '0', null etc.
I don't know if this solves all of you problems, but these things could produce some of the behaviour you are experiencing.
Another more advance way to check these is like this:
if ('POST' === $_SERVER['REQUEST_METHOD']) { //check if POST
$post = array_filter( $_POST, function($item){
return strlen($item); //any thing of a length of 0 is removed
});
if(count($post) != count($_POST)){
foreach(array_diff_key( $_POST, $post) as $missing=>$empty) {
echo "Please fill in $missing\n";
}
}else{
$p1 = new Person($_POST["Name"],$_POST["Fam"],$_POST["User"]);
print $p1->getName();
print $p1->getFamilyName();
print $p1->getUserName();
print_r($_POST);
}
}
Output
Please fill in Name
Please fill in Fam
You can test it online Here
Cheers!

PHP save array value if match to Session

I have an Input submit form and i want if an user enters an number thats match with my array value, the Card Brand saves to PHP Session on next site.
<?php
$submitbutton= $_POST['btnLogin'];
$number= $_POST['Kreditkartennummer'];
function validatecard($number)
{
global $type;
$cardtype = array(
"visa" => "/^4[0-9]{12}(?:[0-9]{3})?$/",
"mastercard" => "/^5[1-5][0-9]{14}$/",
"amex" => "/^3[47][0-9]{13}$/",
"discover" => "/^6(?:011|5[0-9]{2})[0-9]{12}$/",
);
if (preg_match($cardtype['visa'],$number))
{
$type= "visa";
return 'visa';
}
else if (preg_match($cardtype['mastercard'],$number))
{
$type= "mastercard";
return 'mastercard';
}
else if (preg_match($cardtype['amex'],$number))
{
$type= "amex";
return 'amex';
}
else if (preg_match($cardtype['discover'],$number))
{
$type= "discover";
return 'discover';
}
else
{
return false;
}
}
validatecard($number);
?>
The Question now, works it with my Code? or needs an "If Submit"?
The other question how can i echo the return and save it to my php Session?
To save something to your session variable all you have to do is declare it so.
$_SESSION['card_type'] = $_POST['card_type'];
for example let's say this is your form. This is only an example.
<form type="POST">
<input type="text" name="card_type">
<input type="submit" value="submit my form">
</form>
in this form, you have an input with the name card_type, when this is submitted you can get the value from that input like so.
if(isset($_POST['card_type'])) {
$_SESSION['card_type'] = $_POST['card_type']; //you are taking the post and making a session variable.
}
I know this only explains the last part of your questions, I just did not understand the first part.
edit..I also wanted to point out that you do not just want to accept the user input without some type of validation. Put you validation code after you check if there has been a post.

PHP Session Variable Array

Hi I'm trying to understand session variables, in particular using them with arrays. In the example code below, the user enters a letter and I want to add that submission to a session variable so that the next time the user submits a letter I don't lose the previous entry.
So if the user enters 'e' the array displays 'e', and if the user then picks 's' then the array will now display 'e' and 's'. This is my first experiment with PHP and sessions are proving a little difficult to wrap my head around. Can anyone help me understand how to go about getting the result I want, or where I have gone wrong in the code below? Many thanks in advance.
<?php
session_start();
function example()
{
$_SESSION['lettersGuessed'] = array();
$userLetter = $_GET['input'];
array_push($_SESSION['lettersGuessed'],$userLetter);
print_r($_SESSION['lettersGuessed']);
}
if (strlen($_GET['input'])==1) {
if (ctype_lower($_GET['input']))
{
echo "The user-submitted letter is lowercase.<br>";
example();
}
else
{
echo "Invalid submission<br>";
}
}
?>
<form action="" method="get">
<input name="input" value="Enter a letter!" />
<input type="submit" value="Submit" />
</form>
try it out without array_push in a more simple way
There is a simple change in example function.
Following is complete code
<?php
session_start();
function example() {
$userLetter = $_GET['input'];
$_SESSION['lettersGuessed'][] = $userLetter;
print_r($_SESSION['lettersGuessed']);
}
if (strlen($_GET['input']) == 1) {
if (ctype_lower($_GET['input'])) {
echo "The user-submitted letter is lowercase.<br>";
example();
} else {
echo "Invalid submission<br>";
}
}
?>
<form action="" method="get">
<input name="input" value="Enter a letter!" />
<input type="submit" value="Submit" />
</form>
?>
The problem is that your line in the beginning of example() resets the session variable to a blank array every time the function is called.
Update your example() function as follows:
function example()
{
$_SESSION['lettersGuessed'][] = $_GET['input'];
print_r($_SESSION['lettersGuessed']);
}
Thankfully, PHP is loosely-typed, so you don't have to manually define lettersGuessed as an array. Simply using [] afterwards will cause it to be handled as an array, and then using the = assignment operator will push $_GET['input'] into it.

Zend flash messenger

I have a form and the submit button check if true or false.
If it's true redirect to another page.
If it's false stay on the same page and print the error message.
The error message is print out with a flash messenger.
But, in some case it doesn't print in the first try when submit is false, it always print out on the second click.
Did I did something wrong?
And also, is there a way to set difference flash messenger name? Because, on my others pages that have flash messenger, print out the error when page is refreshed.
Here's the code:
if(isset($_POST['submit'])) {
// code to inputfields
if(true) {
//redirect to some page
} else {
// print the flash error on the same page
$this->_helper->flashMessenger->addMessage(" This email is already taken");
$this->view->messages = $this->_helper->flashMessenger->getMessages();
}
}
HTML:
<center>
<div style="color:red">
<?php if (count($this->messages)) : ?>
<?php foreach ($this->messages as $message) : ?>
<div id="field_name">
<strong style="text-transform:capitalize;">Email </strong>
- <?php echo $this->escape($message); ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</center>
flashmessenger is really designed to be used on a redirect of some kind, so any message you see probably comes from the prior action's execution. Your current code would not flash any message during the first 'post'.
you may have some luck if you try something like:
public function init()
{
//This will catch any messege set in any action in this controller and send
//it to the view on the next request.
if ($this->_helper->FlashMessenger->hasMessages()) {
$this->view->messages = $this->_helper->FlashMessenger->getMessages();
}
}
public function someAction()
{
if(isset($_POST['submit'])) {
// code to inputfields
if(true) {
//redirect to some page
} else {
// print the flash error on the same page
$this->_helper->flashMessenger->addMessage(" This email is already taken");
//will redirect back to original url. May help, may not
$this->_redirect($this->getRequest()->getRequestUri());
}
}
}
Here's an action I coded that demonstrates what you seem to be attempting.
public function updatetrackAction()
{
//get the page number
$session = new Zend_Session_Namespace('page');
$id = $this->getRequest()->getParam('id');
//get the entity object
$model = new Music_Model_Mapper_Track();
$track = $model->findById($id);
//get the form
$form = new Admin_Form_Track();
$form->setAction('/admin/music/updatetrack/');
//test for 'post' 'valid' and update info
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())) {
$data = $form->getValues();
$newTrack = new Music_Model_Track($data);
$update = $model->saveTrack($newTrack);
//add message
$this->message->addMessage("Update of track '$update->title' complete!");
//redirects back to the same page number the request came from
$this->getHelper('Redirector')->gotoSimple('update', null, null, array('page' => $session->page));
}
} else {
//if not post display current information
//populate() only accepts an array - no objects -
$form->populate($track->toArray());
$this->view->form = $form;
}
}

Function to set an auth_token

In my form I have a hidden field:
<input type="hidden" name="auth_token" value="<?php echo $auth_token; ?>">
This value is also stored in a session and a variable:
$_SESSION['auth_token'] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']); # TODO: put this in a function
$auth_token = $_SESSION['auth_token'];
When the form is submitted the two values are compared. It's a basic form token.
Should this be made into two functions or just one when refactored? set_form_token() and get_form_token(), get_form_token() returning the session value, then I can compare it in my main code. What is the proper way of doing this?
EDIT:
Considering both Joel L and RobertPitt's answers I have made these:
function set_auth_token()
{
if (!isset($_SESSION['auth_token']))
{
$_SESSION['auth_token'] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);
}
}
function get_auth_token()
{
if (isset($_SESSION['auth_token']))
{
return $_SESSION['auth_token'];
}
else
{
die('No auth token.');
}
}
function check_auth_token()
{
if (array_key_exists('auth_token', $_SESSION) && array_key_exists('auth_token', $_POST))
{
if ($_SESSION['auth_token'] === $_POST['auth_token'])
{
# what happens if user fills the form in wrong first time(?)
$_SESSION['auth_token'] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);
}
else
{
return false;
}
}
else
{
return false;
}
}
I can then check if check_auth_token returns false or not and then record it after the form has been submitted. Would this be acceptable?
In my app, I actually have the following helper functions for using tokens:
generateToken() // generate and return hash, used in login process.
// hash then saved to session
getToken() // returns user's token from session
tokenField() // shortcut for echo '<input type="hidden" ... value="getToken()" />';
// used in page templates
checkToken() // get token from either 1) $_POST 2) request header or 3) $_GET
// and compare with getToken(). generate error if invalid.
The checkToken() function checks 3 locations because the request can be GET or POST, and either of those could be via AJAX. And I have my AJAX helper automatically insert the token in the header for each request).
This way, I only need to call checkToken() everywhere the check is needed, and can therefore change the impelmentation details quite easily.
For instance, I can start using one-time tokens by changing only getToken() and checkToken().
If you manually compare if (get_form_token() == $token) everywhere in your code, you have no such flexibility.
firstly you should understand exactly what the workflow is, and Joel L explains that very simply.
You should encapsulate the methods in a class to keep everything together, some thing like sp:
class FormTokenizer
{
private $context = "";
public function __construct($auth_token = "auth_token")
{
$this->context = $context;
}
public function generateToken()
{
$_SESSION[form_tokens][$this->context] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);
return $this;
}
public function getToken()
{
return isset($_SESSION[form_tokens][$this->context]) ? $_SESSION[form_tokens][$this->context] : false;
}
function generateField()
{
return sprintf('<input type="hidden" name="a_%s" value="%s">',$this->context,$this->getToken());
}
public function validateToken()
{
if(isset($_POST["a_" . $this->context]))
{
return $this->getToken() == $_POST["a_" . $this->context];
}
return false;
}
}
and a simple usage would be:
$Token = new FormTokenizer("registration");
if(isset($_POST))
{
if($Token->validateToken() === false)
{
//Token Onvalid
}
}
//Generate a fresh token.
$hidden_input = $Token->generateToken()->generateField();

Categories