PDO select prepared statement does not work - php

This is a snippet of code from source code, which I made to practice my PHP skills. After submitting the login form, I try to see if the username and password that the user submitted using the login form matches with the one stored on database. If yes then "Your username and password matches what I have!" (obviously this is not going to be the final echo but just to see what echo out of the two will it bring). If I give correct creds (user/pass) or incorrect one, it echoes out "Your username and password DOES NOT matches what I have!" block. I don't see any problem with the code, I ran out of ideas.
Part of the code inside config.php (which I have included) is a setup of the database, with a table of registration and few fields, of which username and password fields does exist hence the names.
user is value of the name tag on login form for Username and pass is value of the name tag on login form for Password.
<?php
include("config.php");
if(isset($_POST['submit'])) {
$stmt = $db->prepare("SELECT * FROM registration WHERE username = :username AND password = :password");
$stmt->execute(array("username" => $_POST['user'], "password" => $_POST['pass']));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if(($_POST['user'] == $result['username']) && $_POST['pass'] == hash("sha256",$result['password'])) {
echo "Your username and password matches what I have! <html><br /></html>";
} else {
echo "Your username and password DOES NOT matches what I have! <html><br /> </html>";
}
}
?>

You've got one concept of password storage backwards: your code compares $_POST['pass'] to the hash of the string in the database. So users are required to enter a SHA256 hash of their password? And you store plaintext password in the database? I don't think so.
It should be the other way around. You allow users to enter their password, then you hash the string they enter. Then compare that to what's stored in the database, which should also be a hashed string.
$pass_hash = hash("sha256", $_POST["pass"]);
$stmt = $db->prepare("SELECT * FROM registration WHERE username = :username AND password = :password");
$stmt->execute(array("username" => $_POST['user'], "password" => $pass_hash));
You don't have to use an if() to test the results. Just test if the query returns zero rows, or not. If it returns any rows, then you found a match.
Also don't assume fetch() returned a row. If there was no row, it returns NULL, so using that row as an associative array will throw an error. Test to see if the row is non-null before dereferencing it.
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// username and password matched a row
echo "Your username and password matches what I have! <html><br /></html>";
} else {
// no matching username
echo "Your username and password DOES NOT matches what I have! <html><br /> </html>";
}
Here's an alternative variation I prefer: I just look for a row matching the username, and I return the hashed password string. Then I compare in application code. This way I can tell if they gave a legitimate username, but the wrong password. You don't necessarily want to reveal that to the user, but you might want to track it in your app so if someone is trying dozens of wrong passwords for the same username, you could lock the username or log an alert for the operator or something.
$stmt = $db->prepare("SELECT password FROM registration WHERE username = :username");
$stmt->execute(array("username" => $_POST['user']));
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$pass_hash = hash("sha256", $_POST["pass"]);
if ($pass_hash == $row['password']) {
echo "Your username and password matches what I have! <html><br /></html>";
} else {
// username exists, but wrong password
echo "Your username and password DOES NOT matches what I have! <html><br /> </html>";
}
} else {
// no matching username
echo "Your username and password DOES NOT matches what I have! <html><br /> </html>";
}

Related

Why are my variables coming up as undefined, des?

User registration works fine. After registration, this login page is opened and the message comes up that password, username and hash are undefined variables on my select line and when I echo the hash.
When trying to login "Invalid login credentials" error pops up, but also "Password is valid", and the hash is printed as well.
if (isset($_POST['username']) and isset($_POST['password'])){
// Assigning posted values to variables.
$username = cleanData($_POST['username']);
$password = cleanData($_POST['password']);
$hash = password_hash($password, PASSWORD_DEFAULT);
$verify = password_verify($password, $hash);
if(password_verify($password, $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
}
// Checking if the values exist in the database or not
$query = "SELECT * FROM `user` WHERE (username='$username') AND (password='$password')";
echo $hash;
$result = mysqli_query($connection, $query) or die(mysqli_error($connection));
$count = mysqli_num_rows($result);
// If the posted values are equal to the database values, then session
is created for the user.
if ($count == 1){
$_SESSION["loggedIn"] = true;
$_SESSION['username'] = $username;
}else{
// error for not matching credentials
$fmsg = "Invalid Login Credentials.";
I suspect that I have done something horribly wrong with the placement and requirements of my SELECT statement , but it still does not explain why these variables are coming up as undefined. Perhaps I can move the SELECT statement to replace the "password is valid" message and go from there?
CleanData is a function to sanitise input.
So, the issue is you're kind of doing this:
if (username and password are set) {
username = xxx
password = xxx
hash password
verify password
display results
}
do sql query based on username and password
So, you've got code outside of your original IF trying to utilize variables that might not have been created.
Your SQL query and all code after that will be called even if you did not pass username and password to the php page.
You might be better off doing something like this at the beginning of your script:
if (username and password are not both set in post vars)
display error
exit
}
username = xxx
password = xxx
Then you can be sure that those vars definitely are defined without having to check over and over in the page.
Also, the pseudocode is on purpose. Trying to get my message across in layman's terms :)
With this code, you will always receive the "password is valid" message, because you are verifying the password that the user entered against the hash that you just generated from that same password!
<!-- Incorrect code: This always determines the password is valid! -->
$hash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($password, $hash)) {
echo 'Password is valid!';
}
You are supposed to use password_hash when you are first inserting the password into the database (that way, you aren't storing the actual password, just a hash). Then, when your user logs in with their username, look in the database for a user with that username. If you find a user with that username, then you use password_verify to check that the $password variable matches the hash that was stored in the database with that user.
Check out this answer to a similar question to see a fleshed out example of login code.

Trying to verify a hashed password from database with password from login form

I am making a registration and login form, which asks for the user's email and password. In my registration file I hashed the password provided by the user, and stored it in the database, with the function password_hash. In my login form I tried to verify the password provided by the user with the stored hashed password in the database, but it fails. I used the password_verify function. Here is a snippet of the registration code:
Registration file snippet
if(!isset($error)){
//hash the password
$hashedpassword = password_hash($_POST['password'], PASSWORD_DEFAULT);
echo $hashedpassword;
try {
$sql = "INSERT INTO users (mail, password, province) VALUES (:mail, :password, :province)";
$stmt = $db->prepare($sql);
//Bind variables
$stmt->bindValue(':mail', $mail);
$stmt->bindValue(':password', $hashedpassword);
$stmt->bindValue(':province', $province);
//Execute the statement and insert the new account.
$result = $stmt->execute();
//If the signup process is successful.
if($result){
echo $hashedpassword;
exit;
}
}
catch(PDOException $e) {
$error[] = $e->getMessage();
}
}
Hashed passwords in database
For these passwords I get the following hashed passwords, which are stored in the database:
football:
$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRMiUUQu8dtWm$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRMiUUQu8dtWm
cricket:
$2y$10$Pyoz1XC0skRjHLjxHdrYYeYplY98w4uOp23QpZb/VNN0y41/6YPJC$2y$10$Pyoz1XC0skRjHLjxHdrYYeYplY98w4uOp23QpZb/VNN0y41/6YPJC
The type for the password row is varchar(255) and the collation is utf8mb4_general_ci The passwords are stored like this:
$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRM...
$2y$10$Pyoz1XC0skRjHLjxHdrYYeYplY98w4uOp23QpZb/VNN...
When I hover over the passwords it says 'Original length 60'.
Login file snippet
This is a snippet of my login file code:
$mail = htmlspecialchars_decode($_POST['mail'], ENT_QUOTES);
if(!filter_var($mail, FILTER_VALIDATE_EMAIL) and !empty($_POST['mail'])) {
$error[] = 'Please enter a valid email address';
}
$stmt = $db->prepare('SELECT mail, password FROM users WHERE mail = :mail');
$stmt->execute(array(':mail' => $mail));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if(!empty($row['mail'])){
$error[] = 'Email provided is good.';
}
$password = $_POST['password'];
$stmt = $db->prepare('SELECT password FROM users WHERE password = :password');
$stmt->execute(array(':password' => $password));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$checkpass = $row['password'];
echo $checkpass;
if(password_verify($password, $row['password'])) {
$error[] = 'Password provided is good.';
}
Checking whether the email can be found in the database works fine, as it gives me the error message (which I need to change to a normal message).
But I can't get the password verification working. I tried to see what the code pulls out the database with $checkpass = $row['password']; and
echo $checkpass;
But it doesn't return anything (maybe because it only returns a 0 or 1 value?).
Maybe it has to do something with the way I try to select the hashed password out of the database? Or the way I insert them in the database, or the MySQL table options? It may be a simple fix but I tried many different things and I couldn't get it to work.. Hope you guys can help!
The second query seems to be useless since in the first query you already select the mail and password fields. So you should just need to execute the first query, check if the user is valid and then check the password with the password_verify method.
Your second query fails (probably) because in the condition you pass the cleartext but in the DB there is the hashed password so you will never find anything. To check print the second query before the execution.
Before executing query for password check in login you should create hashed password for the input password and that hashed password need to be compared

PHP hash_password function

Basically, I've just started working with PHP, and am trying to get to grips with the password_hash function. When a user registers I hash their password using:
$hashed_password = password_hash($p, PASSWORD_DEFAULT);
Then, that hashed password is stored in my database. I then want to retrieve the password for login. So my code is written so that once the form is submitted, the email and password strings are sanitized, it the checks that they're not blank, once that's done, I take the user entered password, and hash it using:
$hash = password_hash($password, PASSWORD_DEFAULT);
Once again. Once this has done I connect to my DB, and try to select the user using:
$q = "SELECT * FROM users
WHERE email='$email' AND password='$hash'";
However. When debugging I've noticed that the user entered string, despite being the same as the string entered when signing up is different when hashed. so I've been echo'ing $hash and getting:
$2y$10$LQ55Q1DUqIgRx/2hgnbrnuQrYvrrBrq4WEFmV8TuxII6rDocaWzt2
but the exact same string "password" is stored in the db as:
$2y$10$omNPA7cviUm.6asuhJIJ8Or.m9WeHhJMkCqYYijel5g.NflbdVnV.
How do I get it so that when the user enters their password, it hashes the string and matches the one in the DB, so that they can log in? Am I missing something
Cheers
You'd need something like this:
$hashed_password = mysql_result(mysql_query("SELECT password FROM users WHERE email='$email'"));
$match = password_verify( $password, $hashed_password );
if($match){
echo 'Password is valid';
} else {
echo 'Password is not valid' ;
}

Verify password hash using password_verify and MySQL

I'm trying to store an encrypted password in MySQL and as for the register part it works as it should how ever when i try to do the login things go south.
I can not verify $_POST['password'] against the hash stored in MySQL.
I have no idea what I'm doing wrong.
Here is my register.php which works as it should:
register.php (working)
$post_password = mysqli_real_escape_string($_POST['password']);
$password_hash = password_hash($post_password, PASSWORD_BCRYPT);
mysqli_query goes here...
login.php (not working)
$con = mysqli_connect("XXX","XXX","XXX","XXX");
$post_username = mysqli_real_escape_string($con,$_POST['username']);
$post_password = mysqli_real_escape_string($con,$_POST['password']);
// Getting the stored Hash Password from MySQL
$getHash = mysqli_fetch_assoc(mysqli_query($con, "SELECT * FROM anvandare WHERE username = '$post_username'"));
$got_Hash = $getHash['password'];
// Checking if what the user typed in matches the Hash stored in MySQL
// **This is where it all goes wrong**
if (password_verify($post_password, $got_Hash)) {
echo "The posted password matches the hashed one";
}
else {
echo "The posted password does not match the hashed one";
}
When I run the code above I get the "Correct password" message by just entering the username and leaving the password field out.
What am I missing?
Actually you need to make sure that you are allowing more than 100 characters in your password column so that all the hashed password can be saved in the field. This was also happening with me, the script was correct and everything was working fine but the only mistake I was doing was that I didn't allow more than 40 characters in the password field which was the biggest error. After incrementing the maximum limit from 40 to 100, everything is working fine:)

How Can I Make This Login System More Secure

I have created this php login script. I was wondering weather it was secure and if not how could I improve it.
PHP Script
<?php
include_once ("ConnectToMySql.php");
session_start();
$username = $_POST['username'];
$username = mysql_real_escape_string($username);
$password = $_POST['password'];
$password = sha1($password);
$query = "SELECT password FROM users WHERE username = '$username';";
$result = mysql_query($query);
if(mysql_num_rows($result) < 1)
{
echo "This Username Is Not Registered!";
exit;
}
if(mysql_num_rows($result) == 1)
{
if ($password == $result)
{
echo "Logged In!";
}
else echo "Wrong Password!";
}
?>
Thanks
A first tip could be to show a common error for both invalid login cases: invalid username or password. That way an eventual attacker wouldn't know if the username is valid or not.
You could also make a single query matching both username and password. You would probably need more user information (to store in session?), so it would be a good idea to select those fields instead of the password (e.g. id, name).
Regarding the hashed password stored in the database, you could add a SALT to improve security.
http://en.wikipedia.org/wiki/Salt_%28cryptography%29
What I would do is change the query to the following:
"SELECT COUNT(*) FROM users WHERE username = '$username' AND password='$password';"
That way, you don't have to check if the password is correct afterwards (and you don't have to pass the sensitive data as well), you only have to check if the numbers of rows returned equal 1 and you can produce a single error message for both username/password.

Categories