Unable to extract password hash from database with prepared statements - php

EDIT: To clarify, I am unable to extract the hashed password from my database using prepared statements.
I'm trying to create a login system that uses prepared statements, password_hash and password_verify.
I have created the registering form that creates the user, with the hashed password using password_hash($_POST['password'], PASSWORD_DEFAULT);
This works properly.
However, I am now stuck on creating the login form.
I am trying to get the password hash that gets stored when a user registers but I cannot get it to work with prepared statements.
This is what I currently have.
<?php
require('db.php');
if(isset($_POST['submit'])) {
$stmt = $connect->prepare('SELECT user_name, user_password FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
}
}
?>
How do I use the data that I got from the select query? And how do I use it to verify the password?
I tried:
$stmt->store_result();
$stmt->bind_result($loginUsername, $hash);
That only stored the username, but not the password hash and I have no clue why.
Verifying the password would use this?
password_verify($password, $hash);
UPDATE
<?php
require('db.php');
if(isset($_POST['submit'])) {
$stmt = $connect->prepare('SELECT user_name, user_password FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
// Get query results
$result = $stmt->get_result();
// Fetch the query results in a row
while($row = $result->fetch_assoc()) {
$hash = $row['user_password'];
$username = $row['user_name'];
}
// Verify user's password $password being input and $hash being the stored hash
if(password_verify($password, $hash)) {
// Password is correct
} else {
// Password is incorrect
}
}
}
?>

Read this PHP MANUAL.Try this:
<?php
require('db.php');
if(isset($_POST['submit'])) {
$stmt = $connect->prepare('SELECT user_name, user_password FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
// Get query results
$stmt->bind_result($user_name,$hash);
$stmt->store_result();
// Fetch the query results in a row
$stmt->fetch();
// Verify user's password $password being input and $hash being the stored hash
if(password_verify($password, $hash)) {
// Password is correct
} else {
// Password is incorrect
}
}
}
?>
This is how I created my login system:
$stmt = mysqli_prepare($link,"SELECT user_email,user_password,user_firstname,user_lastname,user_role,username FROM users WHERE user_email=?");
mysqli_stmt_bind_param($stmt,"s",$email);
mysqli_stmt_execute($stmt);
confirmQuery($stmt);
mysqli_stmt_bind_result($stmt,$user_email,$user_password,$user_firstname,$user_lastname,$user_role,$username);
mysqli_stmt_store_result($stmt);
mysqli_stmt_fetch($stmt);
if(mysqli_stmt_num_rows($stmt) == 0)
relocate("../index.php?auth_error=l1");
else{
if(password_verify($password,$user_password)){
$_SESSION['userid'] = $user_email;
$_SESSION['username'] = $username;
$_SESSION['firstname'] = $user_firstname;
$_SESSION['lastname'] = $user_lastname;
$_SESSION['role'] = $user_role;
if(isset($_POST['stay-logged-in']))
setcookie("userid", $email, time() + (86400 * 30), "/");
relocate("../index.php?auth_success=1");
}else
relocate("../index.php?auth_error=l2");
}
mysqli_stmt_close($stmt);

Related

How to verify password whith 2 different forms?

I have 2 forms : one for Registration and one for Login ([not on the same page, one is a modal][1])
(That's why I did 2 issets at the beginning)
The Registration one is working.
However the Login doesn't work because a User can log in with any password.
I want to verify username/email and of course password. How can I do it ?
Thank you!
Here is my code :
// REGISTRATION
if (isset($_POST['reg_user']) || isset($_POST['login_user'])) {
$username = mysqli_real_escape_string($db, $_POST['name']);
$email = mysqli_real_escape_string($db, $_POST['email']);
$password = mysqli_real_escape_string($db, $_POST['password']);
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$query = "SELECT * FROM utilisateur WHERE pseudoUtil='$username' OR mailUtil='$email'";
$results = mysqli_query($db, $query);
if(mysqli_num_rows($results) == 1){
$_SESSION['message'] = "User already exists !";
}
else{
mysqli_query($db, "INSERT INTO utilisateur (pseudoUtil, mailUtil, pwdUtil) VALUES ('$username', '$email', '$hashed_password')");
$_SESSION['message'] = "Registration complete :)";
}
// LOGIN
if (isset($_POST['login_user'])) {
$query2 = "SELECT $hashed_password FROM utilisateur WHERE pseudoUtil='$username' OR mailUtil='$email'";
$results2 = mysqli_query($db, $query2);
if(mysqli_num_rows($results2) == 1){
$_SESSION['username'] = $username;
header('location: index.php');
}
else{
}
}
}
else{
}
[1]: https://i.stack.imgur.com/fCdAV.png
registration needs to create the password hash and save it to the database, log in needs to pull the hash from the database and compare to the password
both of these tasks should be complete isolated from each other
this means your code should look more like this
note this is an example only not tested as working
POST /register body: username=someone#some.where&password=123456789
function Register(){
$stmt = $mysqli->prepare("SELECT count * as count FROM users WHERE email=?");
$stmt->bind_param("s", $_POST["username"]);
$stmt->execute();
$result = $stmt->get_result();
if($result->fetch_array(MYSQLI_ASSOC)["count"]>0)
{
return "User already exists"
}
else
{
$hash = password_hash($_POST["password"],PASSWORD_DEFAULT);
$stmt = $mysqli->prepare("INSERT INTO users (username, hash) values (?,?)");
$stmt->bind_param("ss", $_POST["username"], $hash);
$stmt->execute();
$result = $stmt->get_result();
//either return success or set up as a successful login and perform login action
}
}
POST /login body: username=someone#some.where&password=123456789
function Login(){
$stmt = $mysqli->prepare("SELECT hash FROM users WHERE email=?");
$stmt->bind_param("s", $_POST["username"]);
$stmt->execute();
$result = $stmt->get_result();
if(password_verify($_POST["password"], $result->fetch_array(MYSQLI_ASSOC)["hash"]))
{
//do successful login
}
else
{
//log in failed
}
}

Login page keeps showing error PHP and MySQL

I am having issues getting some simple (or it seems simple) coding to cooperate. I've tried stripping it completely and typing everything out. Here is the code:
<?php
session_start();
if(isset($_POST['login'])) {
$username = trim($_POST['username']);
$password = md5(trim($_POST['password']));
include('includes/admin.php');
$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$result = mysqli_query($con, $sql);
if(mysqli_num_rows($result) == 0) {
echo '<p>Incorrect login.<br>Return to Login Page</p>';
} else {
$_SESSION['user'] = $username;
echo '<p>Login successful.<br>Go to Admin Page</p>';
}
}
?>
The goal is to have it redirect to the login page if unsuccessful and to redirect to another admin page if successful. I keep getting the "Incorrect Login" error, even when I type in the correct username and password.
Side Note: I know to redirect, I need to use header('Location: link.php'), it is not included for testing purposes.
If you didn't save your password as MD5 hash in your database you will never match it, cause in the line above you hash the password via MD5 before using in the query.
MD5 isn't secure! Use the PHP internal functions (password_hash(), password_verify()) to create and check passwords!
Use prepared statements!
Example code:
<?php
// Save a new user password in DB
$username = 'Max User';
$password = 'My_Secr3t_Pa5sw0rd';
$passwordHash = password_hash($password, PASSWORD_BCRYPT);
$stmt = $mysqli->prepare("INSERT INTO `users` (`username`, `password`) VALUES(?, ?)");
$stmt->bind_param("ss", $username, $passwordHash);
$stmt->execute();
// Check user password
$stmt = $mysqli->prepare("SELECT `password` FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if (password_verify($password, $row['password']) {
echo "Password correct";
} else {
echo "Password incorrect!";
}
?>

Getting hashed password with prepared statements

I can't get this to work. I am new to working with prepared statements so i i'm kinda 50/50 on what i'm doing.
Upon registration, the password is hashed with password_hash($pass,PASSWORD_DEFAULT)
Now, i'm trying to get my login page to function with this but i dont know where / how to write it with the password_verify()
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE BINARY username=? AND password=?";
$stmt = $db->prepare($sql);
$stmt->bind_param("ss",$username,$password);
$stmt->execute();
$result = $stmt->get_result();
$num_rows = $result->num_rows;
if($num_rows == 1){
$rows = $result->fetch_assoc();
if(password_verify($password, $rows['password'])){
$_SESSION['loggedin'] = $username;
$_SESSION['country'] = $rows['country'];
$_SESSION['email'] = $rows['email'];
$_SESSION['avatar'] = $rows['u_avatar'];
$_SESSION['is_gm'] = $rows['is_gm'];
$_SESSION['user_lvl'] = $rows['user_lvl'];
$_SESSION['totalposts'] = $rows['post_total'];
$_SESSION['totalcoins'] = $rows['coins_total'];
$_SESSION['totalvotes'] = $rows['vote_total'];
$_SESSION['secquest'] = $rows['sec_quest'];
$_SESSION['secanswer'] = $rows['sec_answer'];
$_SESSION['join_date'] = $rows['join_date'];
header("Location: /index.php");
exit();
}
} else {
echo "<p class='error_msg'>No accounts could be found with the given credentials.</p>";
}
$stmt->free_result();
$stmt->close();
$db->close();
I would assume that the password verify would before if($num_rows == 1) but as i said, i have no idea.
Your query is essentially:
SELECT * FROM users WHERE username=username AND password_hash=plain_text_password
This isn't going to work. If you're relying on PHP password hashing, you can't do a password comparison on the SQL level. Retrieve the password hash from the database then do the password_verify (exclude the password=?) in your WHERE arguments.

Having trouble with PDO queries

Can someone please take a look at this block of code? I am very new to the PDO method, for some reason this keeps causing a 500 error whenever I submit.
I have narrowed it down to this:
Could it be this part? $hash = $stmt['hash'];
if(empty($response['error'])){
$stmt = $db->prepare("SELECT * FROM Login WHERE username= :username"); // Prepare the query
// Bind the parameters to the query
$stmt->bindParam(':username', $username);
//Carry out the query
$stmt->execute();
$hash = $stmt['hash'];
$affectedRows = $stmt->rowCount(); // Getting affected rows count
if($affectedRows != 1){
$response['error'][] = "No User is related to the Username";
}
if(password_verify($password, $hash))
{
$_SESSION['username'] = $_POST['username'];
$_SESSION['userid'] = $stmt['ID'];
}
else
{
$response['error'][] = "Your password is invalid.";
}
}
If you need more info please ask I will be happy to supply anything I can.
You need to fetch the result of the query to have it accessible. I'm not sure this is your issue, I'd think $hash would just be set to Resource Id#x, not what you want but not a 500. Here's how to fetch (http://php.net/manual/en/pdostatement.fetch.php) though
$stmt = $db->prepare("SELECT * FROM Login WHERE username= :username"); // Prepare the query
// Bind the parameters to the query
$stmt->bindParam(':username', $username);
//Carry out the query
$stmt->execute();
//if you will only be getting back one result you dont need the while or hashes as an array
while($result = $stmt->fetch(PDO::FETCH_ASSOC)){
$hashes[] = $result['hash'];
}
Here's a thread on enabling error reporting PHP production server - turn on error messages
Also you don't have to bind to pass values with the PDO. You also could do
$stmt = $db->prepare("SELECT * FROM Login WHERE username= ?"); // Prepare the query
$stmt->execute(array($username));
Your code is really messy. Just to help you with start point:
if (empty($response['error'])) {
if (isset($_POST['username'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $db->prepare("SELECT * FROM Login WHERE username= :username");
$stmt->bindParam(':username', $username);
$stmt->execute();
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$hash = $row['hash'];
if(password_verify($password, $hash)) {
$_SESSION['username'] = $username;
$_SESSION['userid'] = $stmt['ID'];
} else {
$response['error'][] = "Your password is invalid.";
}
} else {
$response['error'][] = "No User is related to the Username";
}
} else {
$response['error'][] = "Username is not set!";
}
}

Blowfish password_verify doesn't do the job

I'm hashing my passwords with blowfish using Anthony Ferrara's password compactibility library. When I hash 'em they're good, BUT when I try to verify the passwords, doing this:
public function Login($username, $postpassword) {
$stmt = $this->mysqli->prepare("SELECT username, password FROM users WHERE username=? AND password=?");
$stmt->bind_param('ss', $username, $password);
$stmt->execute();
$stmt->bind_result($username, $password);
$stmt->store_result();
if($stmt->num_rows == 1) {
while($stmt->fetch()) {
if (password_verify($postpassword, $password)) {
$SESSID = $this->newSession($username);
$_SESSION['admin_user'] = $username;
$_SESSION['last_login'] = time();
header("Location: home.php?SESSID=$SESSID");
exit();
}
}
}
else {
header("Location: index.php?e=false");
exit();
}
$stmt->close();
$stmt->free_result();
}
It tells me that me details are wrong... And YES, i did define the $username and $password:
if(isset($_REQUEST['login'])) {
$username = $_POST['username'];
$postpassword = $_POST['password'];
$users->Login($username, $postpassword);
}
Does anybody see the mistake I made?
You are selecting the user from the database where the username matches the entered username and the password hash matches the entered plaintext password. Of course this will never match anything. You will have to select the username and password from the database only based on the username, then verify the password using password_verify.

Categories