I am working on a Forgot-Password system where users are emailed a ForgotKey code to enter to access a reset password screen. When this ForgotKey is entered into the database, it is hashed. I used a similar system for my signup page and it's working correctly. I copied most of the code over from that system and now I am getting an error that the user's inputted password does not match the hashed password in the database. Am I using the correct password_verify code for this scenario?
$Email = $_SESSION['PWResetEmail'];
$ForgotKey = $_POST['ForgotKey'];
$ForgotKeySQL = "SELECT Email, ForgotKey, ForgotTime, UserID FROM UserTable WHERE Email = ?";
$ForgotKeySTMT = $conn->prepare($ForgotKeySQL);
$ForgotKeySTMT->bind_param("s", $Email);
$ForgotKeySTMT->execute();
$ForgotKeyRESULT = $ForgotKeySTMT->get_result(); // get the mysqli result
while ($ForgotKeyROW = $ForgotKeyRESULT->fetch_assoc()) {
// A: If password matches DO NOT hash, then send user back to forgot.php to retry
$ForgotKeyCheck = password_verify($ForgotKey, $ForgotKeyROW['ForgotKey']);
if ($ForgotKeyCheck == false) { // <----- code is failing here
$ForgotKeySTMT->free_result();
$ForgotKeySTMT->close();
header("Location: ../forgot.php?4");
exit();
}
// A: If password matches hash, then let user pass to next step of forgot password system.
else if ($ForgotKeyCheck == true) { // <---- I want this line to be true
$ForgotTimeFINAL = $ForgotKeyROW['ForgotTime'];
$UserIDTemp = $ForgotKeyROW['UserID'];
$_SESSION['UserIDTemp'] = $UserIDTemp;
$_SESSION['ForgotKey'] = $ForgotKeyROW['ForgotKey'];
$ForgotKeySTMT->free_result();
$ForgotKeySTMT->close();
header("Location: ../forgot.php?3");
exit();
}
else {
$ForgotKeySTMT->free_result();
$ForgotKeySTMT->close();
header("Location: ../forgot.php?2");
exit();
}
}
Related
I've been developing a secure login page for users but somehow the password verification seems not to work when logging in.
The code below seems to locate the username in the database I've created in MySql, but mainly the password doesn't match every time.
I've made all possible changes, tried all advices but still, no success. If anyone has any solutions for this issue it would be greatly appreciated.
Error always displays that the password is not the right one.
Login Page:
<?php
/* User login process, checks if user exists and password is correct */
// Escape email to protect against SQL injections
$username = $mysqli->escape_string($_POST['username']);
$password = $mysqli->escape_string(password_hash($_POST['password'], PASSWORD_BCRYPT));
$result = $mysqli->query("SELECT * FROM `users` WHERE `username`='$username'");
if ( $result->num_rows == 0 ){ // User doesn't exist
$_SESSION['message'] = "User with that username doesn't exist!";
header("location: error.php");
}
else { // User exists
$user = $result->fetch_assoc();
if ( password_verify($_POST['password'], $user['password']) ) {
$_SESSION['email'] = $user['email'];
$_SESSION['first_name'] = $user['first_name'];
$_SESSION['last_name'] = $user['last_name'];
$_SESSION['username'] = $user['username'];
$_SESSION['active'] = $user['active'];
// This is how we'll know the user is logged in
$_SESSION['logged_in'] = true;
header("location: dashboard.html");
}
else {
$_SESSION['message'] = "You have entered wrong password, try again!";
header("location: error.php");
}
}
Registration Page:
<?php
/* Registration process, inserts user info into the database
and sends account confirmation email message
*/
// Set session variables to be used on profile.php page
$_SESSION['email'] = $_POST['email'];
$_SESSION['first_name'] = $_POST['firstname'];
$_SESSION['last_name'] = $_POST['lastname'];
// Escape all $_POST variables to protect against SQL injections
$first_name = $mysqli->escape_string($_POST['firstname']);
$last_name = $mysqli->escape_string($_POST['lastname']);
$email = $mysqli->escape_string($_POST['email']);
$password = $mysqli->escape_string(password_hash($_POST['password'], PASSWORD_BCRYPT));
$hash = $mysqli->escape_string( md5( rand(0,1000) ) );
// Check if user with that email already exists
$result = $mysqli->query("SELECT * FROM users WHERE email='$email'") or die($mysqli->error());
// We know user email exists if the rows returned are more than 0
if ( $result->num_rows > 0 ) {
$_SESSION['message'] = 'User with this email already exists!';
header("location: error.php");
}
else { // Email doesn't already exist in a database, proceed...
// active is 0 by DEFAULT (no need to include it here)
$sql = "INSERT INTO users (first_name, last_name, email, password, hash, active) "
. "VALUES ('$first_name','$last_name','$email','$password', '$hash', 1)";
// Add user to the database
if ( $mysqli->query($sql) ){
$_SESSION['active'] = 0; //0 until user activates their account with verify.php
$_SESSION['logged_in'] = true; // So we know the user has logged in
$_SESSION['message'] =
"Confirmation link has been sent to $email, please verify
your account by clicking on the link in the message!";
header("location: profile.html");
}
else {
$_SESSION['message'] = 'Registration failed!';
header("location: error.php");
}
}
Here's the login/signup form the user utilizes to sign in into the system: "http://riselamagana.byethost4.com/projects/webdev3/production/index.php"
and the database would be:
table "users"
The password hash that was generated for "password_28" was: " $2y$10$W3bOAG0BP/DExr/qpiT0ueVS3YHb2NVeSC3.oMAaVQbHlodJVudK.".
It still gives me the error that the password isn't correct, my guess is that the password when compared don't match, but I'm not sure why.
Any further suggestions would surely be appreciated.
The password hash that was generated for "password_28" was: " $2y$10$W3bOAG0BP/DExr/qpiT0ueVS3YHb2NVeSC3.oMAaVQbHlodJVudK.".
Story checks out.
It still gives me the error that the password isn't correct, my guess is that the password when compared don't match, but I'm not sure why.
// ...
$user = $result->fetch_assoc();
// ...
if ( password_verify($_POST['password'], $user['password']) ) {
// ...
Are multiple rows being returned for $result? Is it possible that you're comparing the wrong hash in this location?
To troubleshoot this, hard-code $_POST['password'] to be "password_28" and see if it still fails. Then revert your change and hard-code your password hash. Does it still fail?
If it fails the first time, you're probably altering $_POST somewhere else in your application and that's causing the validation to fail.
If it fails the second time, first check that you're only getting one row back (otherwise, this is a trivial fix: make sure you use the correct password hahs for the correct user). If you are, you're probably running into an encoding issue with how your password hashes are being stored. Is the database column too short for the password hash? (Generally you want varchar(255) or TEXT for MySQL, since MySQL truncates by default unless you're running in strict mode.)
Finally, I'd like to recommend not using $mysqli->escape_string() and instead adopting prepared statements. Prepared statements are a much more robust strategy for preventing SQL injection in PHP software than escaping.
You're not comparing to the hashed password, you're comparing the raw post password...
//In your code, line 6, you hash the password
$password = $mysqli->escape_string(password_hash($_POST['password'], PASSWORD_BCRYPT));
//On line 16 you don't
if ( password_verify($_POST['password'], $user['password']) ) {
//So try this instead...
if ( password_verify($password, $user['password']) ) {
I am trying to display the error at the end if the use doesn't enter the correct combination of their log in. However, the error message is not showing when I enter the wrong password or email. Any suggestions
<?php
include ("connect.php");
if (isset($_POST["user_login"]) && (isset($_POST["user_pass"]))){
// formatting field via reg replace to ensure email and password only conisists of letters and numbers preg_replace('#[^A-Za-z0-9]#i','',
$login_user = $_POST["user_login"];
$login_password = $_POST["user_pass"];
// password is encryted in DB (MD5) therefore user inputted password will not match encryted password in DB - we have to assign new var
$decrypted_password = md5($login_password);
// Query which finds user (if valid) from DB - Achieving authentication via username and password
$user_query = mysqli_query($connect, "SELECT * FROM users WHERE email = '$login_user' AND password = '$decrypted_password' AND closed = 'no' LIMIT 1");
$check_user = mysqli_num_rows($user_query); // checking to see if there is infact a user which those credentials in the DB
if ($check_user==1){
while ($row = mysqli_fetch_array($user_query)){
$id = $row['user_id'];
$user_type = $row['account'];
}
$_SESSION["user_login"] = $login_user;
// check the user type and redirect according to it
if($user_type == "Student"){
$student_page = "profile_student.php";
header( "Location:{$student_page}" );
} elseif ($user_type == "Landlord"){
$landlord_page = "landlord_profile.php";
header( "Location:{$landlord_page}" );
} elseif ($user_type == "Administrator"){
$admin_page = "admin_profile.php";
header( "Location:{$admin_page}" );
}else {
$refresh_page = "sign_up.php";
header( "Location:{$refresh_page}" ); // refresh page
echo "You have entered an incorrect email or password. Please try again.";
}
}
}
?>
you redirect user if input data is wrong and only after that you try to echo message, thats not how that works. read about headers in php_manual. probably the best way here, is to store error message in session and after redirect check if session error message exists
else {
$refresh_page = "sign_up.php";
$_SESSION['error'] = "your error message"
header( "Location:{$refresh_page}" ); // refresh page
}
in sign_up.php file check if error message exists in session
if(isset($_SESSION["error"])){
echo $_SESSION["error"];
unset($_SESSION["error"]);
}
maybe you should correct this code a little bit))
use unset cause' after you show the message it should be removed from session, in other case if you fail for example 5 times, it will show 5 messages)) also make sure that session is started session_start() hope it helps:)
You only display the error when $user_type doesn't match any of your expected types.
You need a second else after your if ($check_user==1){ block to handle the case where a user with that email or password doesn't exist.
The below code is used on my admin login page, which redirects to admin only page(s) upon a successful login. Via the database values, I need only users with an admin value of 1 to be granted access, while users with an admin value of 0 get prompted an error message similar to the "invalid username or password". Please signify placement of additional code.
Also, please keep in mind that I take code and patch together as best I can to work for me, so I'm not very fluent in php. Any help would be much appreciated.
DATABASE
ID Username Password Admin
1 John •••••• 0
2 Aaron •••••• 1
<?php
require("connect.php");
// Re-display the username if they fail to enter correct password.
$submitted_username = '';
// Determine whether the login form has been submitted
// If it has, run the login code, otherwise display form
if(!empty($_POST))
{
// Retrieve the users info from the database using username
$query = "
SELECT
id,
username,
password,
salt,
email,
admin
FROM users
WHERE
username = :username
";
// The parameter values
$query_params = array(
':username' => $_POST['username']
);
try
{
// Execute query against database
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$login_ok = false;
// Retrieve user data from database. If $row is false, username in not registered
$row = $stmt->fetch();
if($row)
{
// Using the password submitted by the user and the salt stored in the database,
// we now check to see whether the passwords match by hashing the submitted password
// and comparing it to the hashed version already stored in the database.
$check_password = hash('sha256', $_POST['password'] . $row['salt']);
for($round = 0; $round < 65536; $round++)
{
$check_password = hash('sha256', $check_password . $row['salt']);
}
if($check_password === $row['password'])
{
// If they do, then we flip this to true
$login_ok = true;
}
}
// If the user logged in successfully, then we send them to the private members-only page
// Otherwise, we display a login failed message and show the login form again
if($login_ok)
{
// Here I am preparing to store the $row array into the $_SESSION by
// removing the salt and password values from it. Although $_SESSION is
// stored on the server-side, there is no reason to store sensitive values
// in it unless you have to. Thus, it is best practice to remove these
// sensitive values first.
unset($row['salt']);
unset($row['password']);
// This stores the user's data into the session at the index 'user'.
// We will check this index on the private members-only page to determine whether
// or not the user is logged in. We can also use it to retrieve
// the user's details.
$_SESSION['user'] = $row;
// Redirect the user to the private members-only page.
header("Location: index.php");
die("Redirecting to: index.php");
}
else {
// Tell the user they failed
$error = "Invalid Username or Password";
// Show them their username again so all they have to do is enter a new
// password. The use of htmlentities prevents XSS attacks. You should
// always use htmlentities on user submitted values before displaying them
// to any users (including the user that submitted them). For more information:
// http://en.wikipedia.org/wiki/XSS_attack
$submitted_username = htmlentities($_POST['username'], ENT_QUOTES, 'UTF-8');
}
}
?>
Maybe this will work :-
if($check_password === $row['password'] && $row['admin'] == 1)
{
$login_ok = 1;
}else
{
$login_ok = 0;
}
OR
You can change your query
$query = "
SELECT
id,
username,
password,
salt,
email,
admin
FROM users
WHERE
username = :username
admin = 1
";
Can you please help me to figure out how shall I use this if statement to show different content to different type of users.
this is the code that I have already found on another question:
if($_SESSION['usertype'] == 2){ //do stuff here} if ($_SESSION['usertype']) == 1) { //do stuff here }
I want to use this on a page where only members can view the page, and depending on the usertype, it should show different content.
But I'm not able to send the usertype in the login page when a user logs in, this is the code used there (login.php):
<?php
// First we execute our common code to connection to the database and start the session
require("common.php");
// This variable will be used to re-display the user's username to them in the
// login form if they fail to enter the correct password. It is initialized here
// to an empty value, which will be shown if the user has not submitted the form.
$submitted_username = '';
// This if statement checks to determine whether the login form has been submitted
// If it has, then the login code is run, otherwise the form is displayed
if(!empty($_POST))
{
// This query retreives the user's information from the database using
// their username.
$query = "
SELECT
id,
username,
password,
salt,
email
usertype
FROM users
WHERE
username = :username
";
// The parameter values
$query_params = array(
':username' => $_POST['username']
);
try
{
// Execute the query against the database
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
// This variable tells us whether the user has successfully logged in or not.
// We initialize it to false, assuming they have not.
// If we determine that they have entered the right details, then we switch it to true.
$login_ok = false;
// Retrieve the user data from the database. If $row is false, then the username
// they entered is not registered.
$row = $stmt->fetch();
if($row)
{
// Using the password submitted by the user and the salt stored in the database,
// we now check to see whether the passwords match by hashing the submitted password
// and comparing it to the hashed version already stored in the database.
$check_password = hash('sha256', $_POST['password'] . $row['salt']);
for($round = 0; $round < 65536; $round++)
{
$check_password = hash('sha256', $check_password . $row['salt']);
}
if($check_password === $row['password'])
{
// If they do, then we flip this to true
$login_ok = true;
}
}
// If the user logged in successfully, then we send them to the private members-only page
// Otherwise, we display a login failed message and show the login form again
if($login_ok)
{
// Here I am preparing to store the $row array into the $_SESSION by
// removing the salt and password values from it. Although $_SESSION is
// stored on the server-side, there is no reason to store sensitive values
// in it unless you have to. Thus, it is best practice to remove these
// sensitive values first.
unset($row['salt']);
unset($row['password']);
// This stores the user's data into the session at the index 'user'.
// We will check this index on the private members-only page to determine whether
// or not the user is logged in. We can also use it to retrieve
// the user's details.
$_SESSION['user'] = $row;
$_SESSION['usertype'] = $row;
// Redirect the user to the private members-only page.
header("Location: dashboard.php");
die("Redirecting to: dashboard.php");
}
else
{
// Tell the user they failed
print("Login Failed.");
// Show them their username again so all they have to do is enter a new
// password. The use of htmlentities prevents XSS attacks. You should
// always use htmlentities on user submitted values before displaying them
// to any users (including the user that submitted them). For more information:
// http://en.wikipedia.org/wiki/XSS_attack
$submitted_username = htmlentities($_POST['username'], ENT_QUOTES, 'UTF-8');
}
}
?>
What changes do I need to make in this code?
I am quite new to all this, any help is appreciated.
You need to edit the last bit of your if($login_ok) section to set the $_SESSION variables correctly:
if($login_ok)
{
...
$_SESSION['user'] = $row['username'];
$_SESSION['usertype'] = $row['usertype'];
...
}
From what I can see in your code, if the rest of it works correctly then the dashboard.php page should be able to access it like this:
<?php
require("common.php");
if($_SESSION['usertype'] == 2) {
//do stuff here
} elseif($_SESSION['usertype']) == 1) {
//do stuff here
}
?>
Hey This is my login script, using PHP5 and MYSQLi, I just had help spotting errors in my query, but still it will not let me login, even though the username and password are correct and in the database, it just keeps returning the error: your username and password do not match any in our db. But I know they do lol...could any body spot the problem?
//Check if the form has been submitted
if (isset($_POST['login']))
{
//Check if username and password are empty
if ($_POST['username']!='' && $_POST['password']!='')
{
//Create query to check username and password to database
$validate_user = $mysqli->query('SELECT id, username, password, active FROM users WHERE = username = "'.$mysqli->real_escape_string($_POST['username']).'" AND password = "'.$mysqli->real_escape_string(md5($_POST['password'])).'"');
//We check if the query returns true
if ($validate_user->num_rows == 1)
{
$row = $validate_user->fetch_assoc();
//Check if the user has activated there account
if ($row['activated'] == 1)
{
$_SESSION['id'] = $row['id'];
$_SESSION['logged_in'] = true;
Header('Location: ../main/index.php');
}
//Show this error if activation returns as 0
else {
$error = '<p class="error">Please activate your account.</p>';
}
}
//Show this error if the details matched any in the db
else {
$error = '<p class="error">Your username and password are not in our database!</p>';
}
}
//Show this error if the username and password field have not been entered
else {
$error = '<p class="error">Please enter your username and password.</p>';
}
}
Instead of
SELECT ... FROM users WHERE = username = ...
It should be
SELECT ... FROM users WHERE username = ...
If you keep getting problems like this, try storing the query in a variable and echo it, so you can copy-paste it into your database management tool and see if there are any query errors.
To make it most reliable way, I'd suggest to trigger this error according to main error handling settings:
//just in sake of readability
$user = $mysqli->real_escape_string($_POST['username']);
$pass = $mysqli->real_escape_string(md5($_POST['password']));
$sql = "SELECT id, username, password, active FROM users
WHERE username = '$user' AND password = '$pass'";
$res = $mysqli->query($sql) or trigger_error(mysqli->error.$sql);
note that trigger_error function. it will bring error message to the standard error output. On the development PC it will be browser's screen or a log file on the production server.