Trying to implement CSRF token for the first time ever ...
I have an internal $_SERVER["REQUEST_METHOD"] form ...
Most of the stuff online talks about having it done via _$POST php form ...
So ... after reading all that, I've reasoned that since I have it as in internal part, that I should set the token there ...
So this is what I did ... but clearly I'm misunderstanding something here because it's not working ... not just misunderstanding ... I'm also not sure what I'm supposed to do ... so ... if you could explain what I'm supposed to do so I can set it correctly ... I would really appreciate it
<?php
session_start(); //allows use of session variables
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["first-name"])) {
$firstNameErr = "First name is required";
} else {
$first_name = test_input($_POST["first-name"]);
}
if (empty($_POST["last-name"])) {
$lastNameErr = "Last name is required";
} else {
$last_name = test_input($_POST["last-name"]);
}
if (empty($_POST["email"])) {
$emailErr = "Email is required";
} else {
$email = test_input($_POST["email"]);
}
if (empty($_POST["message"])) {
$messageErr = "Message is required";
} else {
$message = test_input($_POST["message"]);
}
if(isset($first_name) && isset($last_name) && isset($email) && isset($message) && isset($token))
{
$_SESSION['first_name'] = $first_name;
$_SESSION['last_name'] = $last_name;
$_SESSION['email'] = $email;
$_SESSION['message'] = $message;
$_SESSION['token'] = $token;
header("Location: SessionsCRSF.php");
}
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
On the same page is the form (placing a snippet, but you get the idea):
<form class="ui form" method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<div class="field">
<label>First Name</label>
<input name="first-name" id="first-name" placeholder="First Name" type="text" value="<?php if(isset($first_name)) { echo $first_name; }?>">
<?php if(isset($firstNameErr)) print ('<span class="error">* ' . $firstNameErr . '</span>'); ?>
</div>
(...)
</form>
But I don't know how to test it via SessionsCRSF.php form that you see listed in the header ...
Here's the snippet of SessionsCRSF.php form since the rest is just PHPMailer stuff:
<?php
session_start();
if ($_POST['token'] == $_SESSION['token'])
{
die('working, yay?');
}
$first_name = $_SESSION['first-name'];
$last_name = $_SESSION['last-name'];
$email = $_SESSION['email'];
$message = nl2br($_SESSION['message']);
require 'PHPMailerAutoload.php';
$mail = new PHPMailer;
EDITED
Ok, so .. this is what I have so far that works:
<?php
session_start(); //allows use of session variables
if ($_SERVER["REQUEST_METHOD"] == "POST" && $_SESSION['token'] == $_POST['token'] && !empty($_SESSION['token'])) {
if (empty($_POST["first-name"])) {
$firstNameErr = "First name is required";
} else {
$first_name = test_input($_POST["first-name"]);
}
if (empty($_POST["last-name"])) {
$lastNameErr = "Last name is required";
} else {
$last_name = test_input($_POST["last-name"]);
}
if (empty($_POST["email"])) {
$emailErr = "Email is required";
} else {
$email = test_input($_POST["email"]);
}
if (empty($_POST["message"])) {
$messageErr = "Message is required";
} else {
$message = test_input($_POST["message"]);
}
if(isset($first_name) && isset($last_name) && isset($email) && isset($message))
{
$_SESSION['first_name'] = $first_name;
$_SESSION['last_name'] = $last_name;
$_SESSION['email'] = $email;
$_SESSION['message'] = $message;
header("Location: contact9SessionsCRSF2.php");
exit;
}
}
else {
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
You have your page, which contains your $_SESSION value, and you have your INPUT value in the hidden field in your HTML form which are the same value.
Page 1:
[SESSION] ... [INPUT]
You then submit the form to the destination address, here Page 2, and then check that your submitted hidden field value is equal to the $_SESSION value, which is not passed by the input form field.
This input value is found from the $_POST array.
Page 2:
[SESSION] ... [POST]
Specifically to your problem, your submitting your form to the PHP_SELF page (generally PHP_SELF is a bad variable to use and it is not encouraged), which is the same page. BUT, your checking of the data is done on the sessionCRSF.php page, so what you should do is update your form to put:
<form action='sessionCRSF.php' ... >
And then at the top of that page your check of the token value should succeed.
You seem to show some confusion as to SERVER request methods, there are GET/POST/PUT and other ones and if you have an
I have an internal $_SERVER["REQUEST_METHOD"] form
what actually is this? If it's a form then it's a GET/POST method, and that's not internal, as far as I am aware - even if it's on the same server it's from one page to another, so the concepts above apply.
Solution
From discussion and clarification I can now see the solution:
In the If statements that handle the form submission, you do not have any handling of the token posted value, $_POST['token']. So you need to add a statement to handle that, in its simplest form, at the point of the code where you set the values for the $_SESSION form data, add a line:
$_SESSION['posted_token'] = $_POST['token'];
That's all you need, then in the sessionCRSF.php you compare these two values so you then have:
if ($_SESSION['posted_token'] == $_SESSION['token'])
{
die('working, yay?');
}
(You had me confused earlier with reference to "internal" forms etc.!)
Edit :
You need to set the original $_SESSION['token'] when the form is generated, NOT when the form is submitted, your code currently creates the $_SESSION['token'] value on every iteration, and because the page self refers it means that the token values -- being random -- will never ever be the same. You need to set
if (form submitted){
save submitted POSTED token
}
else{
/// form not submitted
generate a token and save to session
}
Do not do both of these things on the same iteration!!
Code
Because sometimes it's easier just to see it....
Code has been updated to compare the tokens on POST submission and therefore bypassing the entire need for sending the data to another page to be compared.
<?php
session_start(); //allows use of session variables
if ($_SERVER["REQUEST_METHOD"] == "POST" &&
$_SESSION['token'] == $_POST['token'] && !empty($_SESSION['token'])) {
if (empty($_POST["first-name"])) {
$firstNameErr = "First name is required";
} else {
$first_name = test_input($_POST["first-name"]);
}
...etc...
if(isset($first_name) && isset($last_name) && isset($email) && isset($message))
{
$_SESSION['first_name'] = $first_name;
$_SESSION['last_name'] = $last_name;
$_SESSION['email'] = $email;
$_SESSION['message'] = $message;
header("Location: SessionsCRSF.php");
exit; //ALWAYS end execution after sending location headers.
}
}
else {
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
}
Related
I want to change page after validation in PHP but, it appears on the same page with the validation.
Here is the logical process i want
if validation didnt complete/invalid input
display error messages, and user must input again in the same page.
if form is validated complete with no invalid input.
User will be moved to a new page for reviewing the inputed data.
And this is my PHP
<?php
// define variables and set to empty values
$nameErr = $emailErr = $genderErr = $websiteErr = "";
$name = $email = $gender = $comment = $website = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["name"])) {
$nameErr = "Name is required";
} else {
$name = test_input($_POST["name"]);
}
if (empty($_POST["email"])) {
$emailErr = "Email is required";
} else {
$email = test_input($_POST["email"]);
}
if (empty($_POST["website"])) {
$website = "";
} else {
$website = test_input($_POST["website"]);
}
if (empty($_POST["comment"])) {
$comment = "";
} else {
$comment = test_input($_POST["comment"]);
}
if (empty($_POST["gender"])) {
$genderErr = "Gender is required";
} else {
$gender = test_input($_POST["gender"]);
}
}
if($nameErr == "" && $emailErr == "" && $genderErr == "" && $websiteErr == "") {
header('Location: http://subc.chaidar-525.com');
exit();
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
I use some referance from W3School, and it makes the review of data is in the same page as the form and validation, and i want the user will be transfered to another new page for reviewing their inputed data.
Use a session, roughly like this:
session_start();
if($nameErr == "" && $emailErr == "" && $genderErr == "" && $websiteErr == "") {
$_SESSION['inputdata'] = $_POST;
//A neater version would be to assign all vars, like:
//$_SESSION['gender'] = $gender;
header('Location: http://subc.chaidar-525.com');
exit();
}
on the next page, use this:
session_start();
$input_data = $_SESSION['inputdata'];
The login form works.
The header location works as it shows the details of the previous page.
I don't know how to put it all together.
The login page just refreshes but if I manually go to another page I am logged in. If I go to the page that requires login (which is the page I'm working on) I am not logged in and I am redirected to the login page.
``
http://example.com/articles/login.php?location=%2Farticles%2Fcommentslisting.php
<?php
// login.php
echo '<input type="hidden" name="location" value="';
if(isset($_GET['location'])) {
echo htmlspecialchars($_GET['location']);
}
echo '" />';
?>
<h2>Login Form</h2>
<form role="form" method='post' action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" id="loginform">
<?php
session_start();
?>
<?php
$username = $password = "";
$usernameErr = $passwordErr = $mainErr = "";
$redirect = NULL;
if($_POST['location'] != '') {
$redirect = $_POST['location'];
}
if(isset($_POST["Login"])) {
if (empty($_POST["txtuser"])) {
$usernameErr = "Name is required";
}
else {
$username = test_input($_POST["txtuser"]);
// check if name only contains letters and whitespace
if (!preg_match("/^[a-zA-Z ]*$/",$username)) {
$usernameErr = "Only letters and white space allowed";
}
}
if (empty($_POST["txtpass"])) {
$passwordErr = "password is required";
} else {
$password = test_input($_POST["txtpass"]);
// check if name only contains letters and whitespace
if (!preg_match("/^[a-zA-Z ]*$/",$password)) {
$passwordErr = "Only letters and white space allowed";
}
}
$username = $_POST['txtuser']; //txtuser is the name in the form field
$password = $_POST['txtpass']; //txtpass is the name in the form field
// TO DO: using stmt bind parameter here instead would be more secure
$checkuser = "SELECT * FROM tbl_customer WHERE CustomerName ='$username' AND password ='$password' ";
$run = mysqli_query($connect, $checkuser);
if (mysqli_num_rows($run)>0) {
$_SESSION['user_name'] = $username;
$_SESSION['start'] = time(); // Taking now logged in time.
// Ending a session in 30 minutes from the starting time.
$_SESSION['expire'] = $_SESSION['start'] + (10 * 60);
//header('Location:http://example.com/login/myaccount.php?username=' .$_SESSION['user_name']);
if($redirect) {
header("Location:". $redirect);
} else {
header("Location:login.php");
}
}
else {
$mainErr = "Username and/or password do not match! Try again!";
}
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
checkuser($data);
}
?>
get request url and after login return to this url $_SERVER['REQUEST_URI']
<?php
if(isset($_SERVER['REQUEST_URI'])) {
$rurl= htmlspecialchars($_SERVER['REQUEST_URI']);
}
?>
<input type="hidden" name="location" value="<?php echo $rurl; ?>" />
After login make header to return url
if(!empty($_SERVER['REQUEST_URI'])){
header("Location:$_SERVER['REQUEST_URI']");
}
else{
header("Location:dashbord.php");
}
Ok, using the comments above and some internet research I have got this working. The user needs to log in to the commentlisting page before they can view comments. So the url is saved in session logged in and the user is redirected to the login page.
<?php
// do check to see if user logged in
if (!isset($_SESSION["username"])) {
echo '<script>alert("you must be logged in ")</script>';
$_SESSION['loggedin'] = $_SERVER['REQUEST_URI'];
header("location: login.php?location=" . urlencode($_SERVER['REQUEST_URI']));
exit;
}
?>
After login checks session is set to true and user is redirected back to the url contained in the logged in session with the username appended to the url.
$_SESSION["username"] = true;
if(isset($username)) {
header('Location:' .$_SESSION['loggedin'].'?username=' .$_SESSION['user_name']);
} else {
header('Location:login.php');
}
To get the full url including parameters you can use
header("location: login.php?location=" . urlencode($_SERVER['REQUEST_URI']).$_SERVER['QUERY_STRING']);
I already searched for an answer here, but none of them could help me fix my problem.
I have a form with the following HTML code at the beginning:
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" id="registration_form">
Standard form, whenever there is an error, the user will be redirected back to to registration form. Everytime, he is on that page, the following PHP code will be executed:
<?php
$fnameErr = $lnameErr = $emailErr = $pwErr = $pw_confErr = "";
$fname = $lname = $email = $pw = $pw_conf = "";
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["fname"])) {
$fnameErr = "(Please submit first name)";
}
else {
$fname = test_input($_POST["fname"]);
}
if (empty($_POST["lname"])) {
$lnameErr = "(Please submit last name)";
}
else {
$lname = test_input($_POST["lname"]);
}
if (empty($_POST["email"])) {
$emailErr = "(Please submit email address)";
}
else {
$email = test_input($_POST["email"]);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emailErr = "(Email address is not valid)";
}
}
include ("script/registration_email_compare.php");
if (empty($_POST["pw"])) {
$pwErr = "(Please submit password)";
}
else {
$pw = test_input($_POST["pw"]);
$pwHash = password_hash($pw, PASSWORD_DEFAULT);
}
if (empty($_POST["pw_conf"])) {
$pw_confErr = "(Please confirm password)";
}
else {
$pw_conf = test_input($_POST["pw_conf"]);
}
if ($_POST["pw"] !== $_POST["pw_conf"]) {
$pwErr = "(Please confirm password)";
$pw_confErr = "";
}
if (empty($fnameErr) && empty($lnameErr) && empty($emailErr) && empty($pwErr) && empty($pw_confErr))
{
ob_start();
include ("script/registration_db_add.php");
include ("script/registration_send_mail.php");
header("Location: registration_success.php");
exit;
}
}
?>
My problem now is that the user is added to my database, but he is not redirected to registration_success, but instead is redirected back to registration.php, where an empty page is returned.
I have no idea how to fix that error and couldn't find any suitable solutions, so I'm happy for any help.
Another extra info: my script is working on localhost, but not after I published it, that's pretty weird actually.
I thought of using php header to redirect upon validation successful. However it's seems broken to me. How do I implement one then. Condition is when all the validation is validated then it would only redirect.
<?php
// define variables and set to empty values
$nameErr = $lastnameErr = $emailErr = $passwordErr = $confirmpasswordErr = $checkboxErr= "";
$name = $lastname = $email = $password = $confirmpassword = $checkbox = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["firstname"])) {
$nameErr = "First Name is required";
}else {
$name = test_input($_POST["firstname"]);
}
if (empty($_POST["lastname"])) {
$lastnameErr = "Last Name is required";
}else {
$name = test_input($_POST["lastname"]);
}
if (empty($_POST["email"])) {
$emailErr = "Email is required";
}else {
$email = test_input($_POST["email"]);
// check if e-mail address is well-formed
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emailErr = "Invalid email format";
}
}
if(!empty($_POST["password"]) && ($_POST["password"] == $_POST["confirmpassword"])) {
$password = test_input($_POST["password"]);
$confirmpassword = test_input($_POST["confirmpassword"]);
if (strlen($_POST["password"]) <= '8') {
$passwordErr = "Your Password Must Contain At Least 8 Characters!";
}
elseif(!preg_match("#[0-9]+#",$password)) {
$passwordErr = "Your Password Must Contain At Least 1 Number!";
}
elseif(!preg_match("#[A-Z]+#",$password)) {
$passwordErr = "Your Password Must Contain At Least 1 Capital Letter!";
}
elseif(!preg_match("#[a-z]+#",$password)) {
$passwordErr = "Your Password Must Contain At Least 1 Lowercase Letter!";
}
}
elseif(empty($_POST["password"])) {
$passwordErr = "Password not filled at all";
}
elseif(!empty($_POST["password"])) {
$confirmpasswordErr = "Password do not match";
}
if(!isset($_POST['checkbox'])){
$checkboxErr = "Please check the checkbox";
}
else {
$checkbox = test_input($_POST["checkbox"]);
}
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
header('Location: http://www.example.com/');
Set $error = 1 if any condition get failed , and at the bottom check if($error!=1) then redirect
and you can also use javascript redirect if header is not working
Look at the closing "?>"-Tab. header will generate a html-header, but is a php-function and should be inside the ?php ?> bracket.
Consider using html5 input validation - saves some code and server roundtrips to let the browser do the validation
Omit the closing "?>" altogether. Its not necessary and can lead to hard to see errors when there is content - even blanks - after the "?>"
Consider using the filter_input function with appropriate parameters to access $_POST and set your variables.
I have a simple login form that allows a user to login, although the form is working fine, but there is one condition where i wish to redirect it to someother page, instead of regular index page.
piece of code where i am facing issue is
if($spid=="")
{
header('Location:index.php');
}
else
{
header('Location:new.php?id=$spid');
}
the issue is even if the $spid has a value it is getting redirected to index.php page. can anyone please tell why this is happening
the whole code from which the above code has been extracted is
<?php
$spid=$_GET['spid'];
$emailErr = $pswrdErr = $loginErr = "";
$email = $password = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["email"])) {
$emailErr = "Email is required";
}
else {
$email = test_input($_POST["email"]);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emailErr = "Invalid email format";
}
}
if (empty($_POST["password"])) {
$pswrdErr = "password is required";
}
else {
$password = test_input($_POST["password"]);
}
$sql = "SELECT * FROM usertable where email='".$email."' and password='".$password."' ";
$result = mysqli_query($con, $sql);
if (mysqli_num_rows($result) > 0) {
while($row = mysqli_fetch_assoc($result)) {
$_SESSION['loggedin'] = true;
$_SESSION['email'] = $email;
if($spid=="")
{
header('Location:index.php');
}
else
{
header('Location:new.php?id=$spid');
}
}
}
else {
$loginErr = "Invalid Credentials";
}
}
function test_input($data) {
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="POST" role="form">
<input type="text" class="form-control" name="email">
<input type="password" class="form-control" name="password">
</form>
As you said you are getting value in $spid=$_GET['spid']; So instead of following above mentioned method take your $spid as hidden i/p text inside form and then pass it in your code as
$finalspid=$_POST["spid"]
and then put your if else condition according to $finalspid
Try this:
if(!isset($spid) && $spid==''){
header('Location:index.php');
} else {
header("Location:new.php?id=".$spid);
}