I have looked at the other questions/answers to do with this and have tried to modify my code multiple ways to suit their answers, but have had no success. I have a register form that works fine and successfully adds the user to the database using the password_hash function. Password field is VARCHAR(255) and displays as hashed when entered.
The issue is with the login form. I have tried various ways all day with no success. Below is my current login.php script.
<?php
session_start(); // Starting Session
$error=''; // Variable To Store Error Message
if (isset($_POST['submit'])) {
//error if both boxes empty
if (empty($_POST['email']) || empty($_POST['password'])) {
$error = "Please fill in both boxes";
}
else
{
// connecting, selecting database
require_once 'dbstuff.php';
include 'opendb.php';
// To protect MySQL injection for Security purpose and define $email and $password
$email = mysqli_real_escape_string($cxn,$_POST['email']);
$password = mysqli_real_escape_string($cxn,$_POST['password']);
//selects user = to email given
$sel_user = "SELECT * from Customer WHERE email='$email'";
$result = $cxn->query($sel_user);
//if matched email in DB verifies password given with hashed password in DB
if($result->num_rows ===1){
$row = $result->fetch_array(MYSQLI_ASSOC);
if (password_verify($password, $row['password'])){
echo "match";
//$_SESSION['login_user']=$email; // Initializing Session
//header("location: index.php"); // Redirecting To Other Page
} else {
$error = "email or Password is invalid";
}
}
mysqli_close($cxn); // Closing Connection
}
}
?>
$error variable works fine but still can't see where I am going wrong with the password_verify, keep getting the 'email or password is invalid' error instead of 'match'.
I really would appreciate some feedback on what I have missed out in the code! Thanks :)
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']) ) {
In my login page I am using a phone number and password fields only to login, thereafter, I am creating and storing a session using the phone number.
Insted, I want to echo the username currently logged in to display the current user becasue in my case I am currently only able to display the phone number of the logged in user. How do I do that?
Here is my login script
<?php
// Starting Session
session_start();
include "../script.php";
$error=''; // Variable To Store Error Message
if (isset($_POST['signin'])) {
if (empty($_POST['signinphone']) || empty($_POST['signpassword'])) {
$error = "Phone or Password is invalid";
}
else
{
// Define $username and $password
$phone=$_POST['signinphone'];
$password=$_POST['signpassword'];
// To protect MySQL injection for Security purpose
$phone = stripslashes($phone);
$password = stripslashes($password);
$phone = pg_escape_string($db, $phone); // Set email variable
$password = pg_escape_string($db, $password); // Set hash variable
$pass_crypted = password_hash($password);
// SQL query to fetch information of registerd users and finds user match.
$sql="SELECT usr_id, usr_email, usr_first_name, usr_last_name,
usr_encrypted_password,
usr_salt, usr_stos_id, usr_pers_id, usr_username, usr_updated_at,
usr_created_at, usr_enabled, usr_role_id, usr_jbrn_id,
usr_mobile_number,
stp_acc_id, usr_location, usr_mobile_imei, usr_type
FROM js_core.stp_users
where usr_mobile_number='$phone'
AND usr_encrypted_password='$password'";
$result=pg_query($db, $sql);
$rows = pg_num_rows($result);
if ($rows == 1) {
$_SESSION['phone']=$phone; // Initializing Session
$_SESSION['username'] = pg_fetch_object($result)->usr_last_name;
header("location: ../index.php");
} else {
//echo "0 results";
echo "Try Again the credentials you entered don't much ours";
}
; // Closing Connection
}
}
?>
and Here is my sample code where I want to display the username inplace of the phone
<li>
<?php
if(isset($_SESSION['username'])) {
echo '<li>'. $_SESSION["username"] . '</li>';
echo '<li>
Log Out</li>';
} else {
echo '<a class="signing" href="#login" data-toggle="modal" data-target="#signIn">Login </a>';
}
?>
</li>
There is not one answer to your question.
I'm posting this because it contains an example of all the things that have been mentioned in the comments to your question.
Firstly, you'll notice that there is a new $db connection that uses the PDO. This is the generally accepted way to handle DB connections and is relatively easy to install (if your php version doesn't have it) - there are plenty of examples on SO. I'd assume you'd want this in your script.php since it's common.
I've also swapped out the password hashing function for the native BCRYPT password_hash() function. When you sign the user up, you would then use it like so:
$encryped_password = password_hash($_POST['signpassword'], PASSWORD_BCRYPT);
This contains a uniquely salted password with the default cost.
Following that, you can fetch the user as you were, with the small adjustment to make it a prepared statement. This provides SQL Injection protection and generally makes things cleaner.
You'll then see that after the row is fetched, you can compare the password with the password_verify() function.
Finally to your original issue - I've set the PDO mode to object, so you can access and assign as many properties as you need to in the same way. Only the properties in the SELECT clause will be available in that object.
// Starting Session
session_start(); //I'd suggest this should also go in your script.php
$db = new PDO('pgsql:dbname=mydb;host=localhost;user=myuser;password=mypass');
include "../script.php";
$error=''; // Variable To Store Error Message
if (isset($_POST['signin'])) {
if (empty($_POST['signinphone']) || empty($_POST['signpassword'])) {
$error = "Phone or Password is invalid";
}
else
{
// SQL query to fetch information of registerd users and finds user match.
$sql = 'SELECT usr_id, usr_email, usr_first_name, usr_last_name, usr_encrypted_password
usr_stos_id, usr_pers_id, usr_username, usr_updated_at,
usr_created_at, usr_enabled, usr_role_id, usr_jbrn_id,
usr_mobile_number, stp_acc_id, usr_location, usr_mobile_imei,
usr_type
FROM js_core.stp_users
WHERE usr_mobile_number = :phone_number';
$stmt = $db->prepare($sql);
$stmt->execute(['phone_number' => $_POST['signinphone']]);
if ($row = $stmt->fetch(PDO::FETCH_OBJ)){
if(password_verify($_POST['signinpassword'], $row->usr_encrypted_password)) {
$_SESSION['phone'] = $row->usr_mobile_number; // Initializing Session
$_SESSION['username'] = $row->usr_username;
header("location: ../index.php");
} else {
//valid user, invalid password
}
} else {
//Invalid user
echo "Try Again the credentials you entered don't much ours";
}
}
}
I've made the assumption that you're running at lease PHP 5.5 for the password_hash, but there is a polyfill if not.
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.
I am trying to use the below code to create a login form. The problem being after registration when I am trying to login, getting an error message "Username or Password don't match" even though email & password are correct. I tried "$num <=1" and allows me to log in but obviously it is not authenticating the login details in that case. Any help will be appreciated.Most importantly this code is working fine on a local server like XAMPP but problem starts when using a host server like hostgator (no issue to connect with the server).
<?php
session_start(); // Starting Session
#Database connection
include('../config/connection.php');
$error=''; // Variable To Store Error Message
if (isset($_POST['submit']))
{
if (empty($_POST['email']) || empty($_POST['password'])) {
$error = '<p class="alert alert-danger">One or either field is missing</p>';
}
else
{
// Define $username and $password
$email=$_POST['email'];
$password = $_POST['password'];
// To protect MySQL injection for Security purpose
$email = stripslashes($email);
$email = mysql_real_escape_string($email);
// SQL query to fetch information of registerd users and finds user match.
$q = "SELECT * FROM users WHERE email = '$email' AND password = md5(SHA1('$password'))";
$r = mysqli_query($dbc, $q)or die(mysqli_error());
$num = mysqli_num_rows($r);
if($num ==1){
$_SESSION['username'] = $email;
header('Location:Index.php');
} else {
$error = '<p class="alert alert-danger">Username or Password don\'t match</p>';
}
mysqli_close($dbc); // Closing Connection
}
}
?>
in your query the $password should not be between the quotes, cause then it will seek for the string instead of the value of the variable.
$q = "SELECT * FROM users WHERE email = '$email' AND password = 'md5(SHA1($password))'";
make sure your password is hashed in your database
Okay.. I am completely new to this PDO stuff.. I have tried to recreate my mysql script (working) to a PDO script (not working).. I have tested that my DB login informations is correctly programmed for PDO..
This is my PDO script...
<?
session_start();
//connect to DB
require_once("connect.php");
//get the posted values
$email=htmlspecialchars($_POST['email'],ENT_QUOTES);
$pass=md5($_POST['psw']);
//now validating the email and password
$sql - $conn_business->prepare( "SELECT email, password FROM members WHERE email='".$email."'");
$sql -> execute();
$count = $sql->rowCount();
$result = $sql -> fetch();
// Now use $result['rowname'];
$stmt = $conn_business->prepare("SELECT * FROM members WHERE email='".$email."'");
$stmt ->execute();
$act = $stmt -> fetch();
//if email exists
if($count > 0)
{
//compare the password
if(strcmp($result["password"],$pass)==0)
{
// check if activated
if($act["activated"] == "0")
{
echo "act"; //account is not activated yet
}
else
{
echo "yes"; //Logging in
//now set the session from here if needed
$_SESSION['email'] = $email;
}
}
else
echo "no"; //Passwords don't match
}
else
echo "no"; //Invalid Login
?>
And this is my old mysql script...
session_start();
require_once("connect.php");
//get the posted values
$email=htmlspecialchars($_POST['email'],ENT_QUOTES);
$pass=md5($_POST['psw']);
//now validating the username and password
$sql="SELECT email, password members WHERE email='".$email."'";
$result=mysql_query($sql);
$row=mysql_fetch_array($result);
$sql2="SELECT * FROM members WHERE email='".$email."'";
$result2=mysql_query($sql2);
$row2=mysql_fetch_array($result2);
$act = $row2['activated'];
//if username exists
if(mysql_num_rows($result)>0)
{
//compare the password
if(strcmp($row['password'],$pass)==0)
{
// check if activated
if($act == "0")
{
echo "act";
}
else
{
echo "yes";
//now set the session from here if needed
$_SESSION['email'] = $email;
}
}
else
echo "no";
}
else
echo "no"; //Invalid Login
Does anybody know, what I have done wrong? It is an automatically script.. It is called through AJAX and return data based on 'no', 'yes' and 'act' that tells the AJAX/jQuery script what to do.. As I said - the mysql script is working, so please if anyone could tell me what I have done wrong with the PDO script..
EDIT:
when it returns the data to the jQuery script, this should happen:
if yes: start session, redirect to page2.php with session started.
else if act: write in a field that the account is not activated.
else: write that email and password didn't match.
The thing is, that when I try to write the correct e-mail and password - it continues to write : "email and password didn't match" instead of redirecting.. When I say that it is not working it is because the mysql script does as described but the PDO script doesn't..
And I have tried to change the 'echo "no";' to 'echo "yes";' to see if the login would start anyway, but somehow it continues to write that the email and password didn't match..
SOLUTION:
I ahven't told this because I thought it was unnecessary, but the reason for it not to work was because of that i have had my old mysql code in comment marks on top of the page, so that the session_start command didn't work.. After deleting the old code it worked, but then I found something else to change, and that is in the PDO script when it is validating it says:
$sql - $conn_business->prepare( "SELECT email, password FROM members WHERE email='".$email."'");
and then I just changed the '-' after $sql to '=' and now, everything works perfectly... Anyhow thank you everybody.. hope this code can help others..
Did you even read the manual before you "started using" PDO?
That is not how prepared statements are supposed to be used! Your code is filled with SQL injections.
Why are you selecting same row twice ?
The strcmp() is not for checing if one string is identical to another.
And hashing passwords as simple MD5 is just a sick joke.
session_start();
//very stupid way to acquire connection
require_once("connect.php");
//get the posted values
$email = htmlspecialchars($_POST['email'],ENT_QUOTES);
if (filter_var( $email, FILTER_VALIDATE_EMAIL))
{
// posted value is not an email
}
// MD5 is not even remotely secure
$pass = md5($_POST['psw']);
$sql = 'SELECT email, password, activated FROM members WHERE email = :email';
$statement = $conn_business->prepare($sql);
$statement->bindParam(':email', $email, PDO::PARAM_STR);
$output = 'login error';
if ($statement->execute() && $row = $statement->fetch())
{
if ( $row['password'] === $pass )
{
// use account confirmed
if ( $row['activated'] !== 0 ) {
$output = 'not activated';
$_SESSION['email'] = $email;
}
$output = 'logged in';
}
}
echo $output;
i believe the second query in your scripts is not necessary you could simple do
SELECT * FROM members WHERE email=:EMAIL AND password=:PWS;
use bindParam method
$qCredentials->bindParam(":EMAIL",$EMAIL);
$qCredentials->bindParam(":PWS",$PWS);
then do more understable outputs rather than yes or no..
try "Unable to login: Invalid credentials supplied" for invalid types of values or "Unable to login: Invalid credentials, couldn't find user" for invalid user credentials.
You could try to start the session after the user has been successfully logged in your IF condition returning yes, and the methods
$PDOstatement->debugDumpParams()
$PDOstatement->errorInfo()
$PDOstatement->errorCode()
will help you understand what went wrong with a query!