So I'm enabling users to create accounts with a username and password. I have managed to encrypt the password when a user creates a new account using:
$hash = password_hash($password, PASSWORD_BCRYPT);
However I'm having trouble with password_verify when logging in, could someone please help me with what I have? I know it's something like this:
password_verify($password, $hash)
But I don't know how to structure it or where to add it in the code. Thanks in advance. This is what I have:
<?php
if (isset($_GET["username"]) && isset($_GET["password"]) ){
$username = $_GET["username"];
$password = $_GET["password"];
$result = login( $username, $password);
echo $result;
}
function makeSqlConnection()
{
$DB_HostName = "";
$DB_Name = "";
$DB_User = "";
$DB_Pass = "";
$con = mysql_connect($DB_HostName,$DB_User,$DB_Pass) or die(mysql_error());
mysql_select_db($DB_Name,$con) or die(mysql_error());
return $con;
}
function disconnectSqlConnection($con)
{
mysql_close($con);
}
function login($username, $password)
{
$con = makeSqlConnection();
$sql = "select * from login where username = '$username' and password = '$password';";
$res = mysql_query($sql,$con) or die(mysql_error());
$res1 = mysql_num_rows($res);
disconnectSqlConnection($con);
if ($res1 != 0) {
return 1;
}else{
return 0;
}// end else
}// end of Function
?>
The general practice is as follows:
Fetch password hash from the database where the username = the inputted username.
If rows are found, then there's a user
Now you compare the inputted password against the hash stored in the database.
I'll outline the above flow in some pseudo code for you here:
$query = SELECT password FROM users WHERE username = '$username'
$data = FETCH_THE_DATA($query);
if(password_verify($USER_INPUTTED_PASSWORD, $data['password'])) {
// password is correct
} else {
// password is in-correct
}
Notes
Stop using mysql_* functions. The library is deprecated as it's unreliable and will be removed in future releases of PHP.
You're better off using PDO or MySQLi Prepared Statements
You should always read the manual - password_verify(), it states clearly that you compare the "user inputted password" against the hashed version which is stored in your database.
Since I'm feeling good and sleepy today, I'll write a bunch of codes.
This is an example how to use PDO with prepared statement. You will have to tweak it according to your needs and you have to check if the post/get not empty as well.
I prefer to use POST request for login so this example will use POST request..
This is my user class. Which use placeholders and binding instead of passing the parameters into the query directly. This will give some protections against SQL injection attack.
class User{
private $dbh;
function __construct(){
$this->dbh = new PDO("mysql:host=".DB_SERVER.";dbname=".DB_NAME.';charset=utf8mb4', DB_USER, DB_PASSWORD) or die('db connect error');
}
function create($username, $password){
$status = false;
try{
$stmt = "INSERT INTO login (username, password)
VALUES (?, ?)";
$qry = $this->dbh->prepare($stmt);
$qry->bindParam(1, $username);
$qry->bindParam(2, $password);
$status = $qry->execute();
}catch(PDOException $e){
$e->getMessage();
}
$qry->closeCursor();
return $status;
}
public function getPassword($username){
$status = false;
try{
$stmt = "SELECT * FROM login WHERE username = ? LIMIT 1";
$qry = $this->dbh->prepare($stmt);
$qry->bindParam(1, $username);
$qry->execute();
$status = $qry->fetch(PDO::FETCH_ASSOC);
}catch(PDOException $e){
$e->getMessage();
}
$qry->closeCursor();
return $status;
}
}
This is how to create the user. Note that I don't check if the username already exist. You can either implement it yourself or use unique index on username column provided that the collation is case insensitive.
I have also increased the cost from the default that is 10 and I defined PASSWORD_DEFAULT to be used because I want the PHP engine to always use the strongest available algorithm (currently bcrypt).
function hashPassword($password){
$password = password_hash($password, PASSWORD_DEFAULT,array('cost' => 16));
return $password;
}
$user = new User;
$_POST['password'] = hashPassword($_POST['password']);
if(!$user->create(trim($_POST['username']),$_POST['password'])){
echo 'Failed creating user';
}else{
echo 'User created';
}
This is how to verify the password.
$user = new User;
$getPassword = $user->getPassword(trim($_POST['username']));
if(!$getPassword){
echo 'Error fetching user';
}else{
if(!password_verify($_POST['password'], $getPassword['password'])){
echo 'Login failed';
}else{
echo 'Login successful';
}
}
Related
What wrong with my code? please need some help cause I dont see any problem. but still password_verify doesnt work.
public function login($username, $password){
global $db;
$sql = 'SELECT id,password FROM '.DB_PREFIX.'admin WHERE username="'.$username.'"';
$result = $db->query($sql);
$row = $result->fetch_assoc();
$pass = $row['password'];
if (password_verify($password,$pass)) {
echo "Valid";
}else{
echo "Invalid";
}
}
This is the password hashing and then save to DB
public function addnewadmin($username,$password)
{
global $db;
$hash = password_hash($password, PASSWORD_DEFAULT);
$sql = "INSERT INTO admin (username, password) VALUES ('".$username."', '".$hash."')";
$result = $db->query($sql);
return true;
}
Let's do this properly.
First, use prepared statements to get rid of SQL injection:
$stmt = 'SELECT id,password FROM '.DB_PREFIX.'admin WHERE username = ?';
$stmt->execute($username);
Then, and I guess that was the problem, fetch the result.
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$pass = $row['password'];
And now, you can verify the password.
As I was changing my MySQLi to PDO, I encountered an error when fetching hashed strings from my users table.
This was the code I used before:
CheckPassword VERIFIES VALID USING MYSQLI
$mysqli = new mysqli("localhost","_USER_","_PASS_","_DB_");
$username = '_USERNAME_';
$pass = '_PASSWORD_';
$sql = "SELECT * FROM `users` WHERE username='$username' LIMIT 1";
$result = $mysqli->query($sql);
if($assoc = $result->fetch_assoc()){
$db_pass = $assoc['userpass'];
require 'PasswordHash.php';
$hash_cost_log2 = 8;
$hash_portable = FALSE;
$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
if($hasher->CheckPassword($pass, $db_pass)) {
echo "valid"; // VERIFIES VALID
} else {
echo "invalid";
}
}
The reason why I switched to PDO was to prevent SQL Injections.
But now: CheckPassword VERIFIES INVALID USING PDO
$pdo = new PDO('mysql:dbname=_DB_;host=localhost', '_USER_', '_PASS_',
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$username = '_USERNAME_';
$pass = '_PASSWORD_';
$stmt = $pdo->prepare('SELECT * FROM `users` WHERE username = :u LIMIT 1');
$stmt->bindParam(':u', $username);
$stmt->execute();
if($fetch = $stmt->fetch(PDO::FETCH_ASSOC)){
$db_pass = $fetch['userpass'];
require 'PasswordHash.php';
$hash_cost_log2 = 8;
$hash_portable = FALSE;
$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
if($hasher->CheckPassword($pass, $db_pass)) {
echo "valid";
} else {
echo "invalid"; // VERIFIES INVALID
}
}
}
How is it that; MySQLi fetches the hashed string different compared to PDO? No matter what encryption I use for hashing the passwords, it CANNOT validate them as true when fetching using PDO, BUT only when fetching using MySQLi?
The reason because when you comparing the password that the user enter and the password that in the database , its different , the pass that the user enter to log in to his account is not hashed while the one in the database is , so we need a way to hash the entered pass and validate it with the already hashed pass in the database . How to do that ? here
This is an example from a code that i use in my Control panel :
<?php
// connect to your database
if(isset($_POST['btn-login']))
{
$User_name = $_POST['userlogin'];
$password_user = $_POST['pass'];
$FetchUserData = $conn->prepare("SELECT * FROM users WHERE userlogin = ?");
$FetchUserData->execute(array($User_name));
$FetchedData = $FetchUserData->fetch(PDO::FETCH_ASSOC);
if ($FetchedData)
{
$password = $FetchedData['userpassword']; // Save the fetched password inside variable
$isPasswordCorrect = password_verify($password_user, $password);
if( $password_user == $isPasswordCorrect )
{
$_SESSION['login_user']=$User_name;
header("location: home.php");
}
else
{
echo "Password is wrong":
}
}
else
{
echo "User is not exist ";
}
}
?>
This Code line is the code used to hash the enterd pass with the exist pass in the database :
$isPasswordCorrect = password_verify($password_user, $password);
Small explanation :
password_verify(parameterA,parameterB)
parameterA : The password that you want it to be validate .
parameterB : the password that you want it to be validated with .(
database that is stored in the database )
Hope this answer be helpful for you .
Basically what would I need to add to this code in the login.php to match the hash created in the register.php:
login.php
if (isset($_POST['Login'])) {
$username = $_POST['email'];
$store_password = $_POST['pword'];
check($username, $store_password);
}
function check($username, $pword){
$conn = mysqli_connect('localhost', 'root', 'root', 'Registrar');
$check = "SELECT * FROM Users WHERE email='$username'";
$check_q = mysqli_query($conn, $check) or die("<div class='loginmsg'>Error on checking Username<div>");
if (mysqli_num_rows($check_q) == 1) {
login($username, $pword);
}
else{
echo "<div id='loginmsg'>Wrong Email or Password</div>";
}
}
function login($username, $pword){
$conn = mysqli_connect('localhost', 'root', 'root', 'Registrar');
$login = "SELECT * FROM Users WHERE email='$username' and pword='$pword'";
$login_q = mysqli_query($conn, $login) or die('Error on checking Username and Password');
if (mysqli_num_rows($login_q) == 1){
header('Location: account.php');
echo"<div id='loginmsg'> Logged in as $username </div>";
$_SESSION['username'] = $username;
}
else {
echo "<div id='loginmsg'>Wrong Password </div>";
}
}
to match the password hash in the register.php
register.php:
$uname = $_POST['uname'];
$email = $_POST['email'];
$pword = $_POST['pword'];
$store_password = password_hash('pword', PASSWORD_BCRYPT, array('cost' => 10));
Any assistance would be appreciated.
You have to use function password_verify like this
if (password_verify($given_password, $stored_password)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
So you have to retrieve the results from db for the given username and compare the password.
In fact
function login($username, $pword){
$conn = mysqli_connect('localhost', 'root', 'root', 'Registrar');
$login = "SELECT email, pword FROM Users WHERE email='$username'";
$login_q = mysqli_query($conn, $login) or die('Error on checking Username and Password');
if (mysqli_num_rows($login_q) == 1){
if(password_verify($pword, mysqli_fetch_field($login_q,1))){
header('Location: account.php');
echo"<div id='loginmsg'> Logged in as $username </div>";
$_SESSION['username'] = $username;
}
else {
echo "<div id='loginmsg'>Wrong Password </div>";
}
}
else {
echo "<div id='loginmsg'>Unknown Username </div>";
}
}
You should separate tasks, you will want to have maybe 2-4 or so functions (or methods via a class). Here is a really simple example of the workflow. I am going to use PDO because I know it better:
// This is just simple but you can make this as elaborate as you want, but
// if you always use the same function to connect, you will will find troubleshooting
// that much easier.
function connection()
{
return new PDO('mysql:host=localhost;dbname=Registrar','root','root');
}
// You want to make a simple validation function where that's all it does,
// you don't want to put a bunch of html in here because you can reuse this function
// elsewhere in other scripts if need be.
function validate($email,$password,$con)
{
// Just look up by email only
$sql = "SELECT * FROM `Users` WHERE `email`= ?";
$query = $con->prepare($sql);
$query->execute(array($email));
$result = $query->fetch(PDO::FETCH_ASSOC);
// If you don't get a row, just return false (didn't validate)
if(empty($result['email']))
return false;
// $result['password'] should have been stored as a hash using password_hash()
return password_verify($password,$result['password']);
}
// Do a quick updater to make it easier on yourself.
// You don't use this in this script but it gives you an idea about what to
// do when you are saving passwords via password_hash()
function updatePassword($email,$password,$con)
{
$hash = password_hash($password, PASSWORD_DEFAULT);
$sql = 'UPDATE `Users` set `password` = ? where `email` = ?';
$query = $con->prepare($sql);
$query->execute(array($hash,$email));
}
session_start();
$con = connection();
// Check there is a post and that post is valid email address
// At this point you can add more messaging for errors...
if(!empty($_POST['email']) && filter_var($_POST['email'],FILTER_VALIDATE_EMAIL)) {
// Run our validation function
$valid = validate($_POST['email'],$_POST['password'],$con);
if($valid) {
$_SESSION['username'] = $_POST['email'];
header('Location: account.php');
exit;
}
else {
die("<div id='loginmsg'>Wrong Password</div>");
}
}
I created a form to insert data(username & password) in sql server. the password there is already encrypted. my problem now is am I going to insert the $encrypt_pass in my parametrized query.
<?php
$pass= $_POST['pass'];
$encrypt_pass=md5($pass);
$params = array($_POST['user'], $encrypt_pass);
$server = "MELODY-PC\SQLEXPRESS";
$options = array("Database"=>"customerdb", "UID"=>"dbadmin", "PWD"=>"melodyjerah");
$conn = sqlsrv_connect($server, $options);
$sql = "SELECT * FROM accounting_login WHERE username = ? and password = ?";
$stmt = sqlsrv_query($conn, $sql, $params);
if(sqlsrv_has_rows($stmt))
{
header("Location: page_accounting.php");
}
else
{
echo "Invalid USERNAME or PASSWORD!";
}
?>
If you have php 5.5, use this
$password = password_hash($password_from_input, PASSWORD_DEFAULT); //store this in db
In login_form.php
$true = password_verify($password_from_input, $password_in_db); // returns TRUE or FALSE
You do not need salt, just a password column will do
From the PDO manual:
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.
I have this code:
<?php
require 'core.inc.php';
if(isset($_POST['user']) AND isset($_POST['pass'])){
if(!empty($_POST['user']) AND !empty($_POST['pass'])){
$user = $_POST['user'];
$pass = $_POST['pass'];
require 'connect.inc.php';
$st = $db_pdo->prepare("SELECT id FROM users WHERE user=? AND pass=?");
$st->bindParam(1, $user);
$st->bindParam(2, $pass);
$st->execute();
$result = $st->fetchColumn();
if($st->rowCount() > 0){
$id_arr = $st->fetch();
$id = $id_arr[0];
$_SESSION['user_id'] = $id;
header('Location: edit.php');
} else { echo 'Username or password incorrect';}
} else { echo 'You must fill in all fields.';}
}
?>
The number of rows returned is always 0, as stated in the manual. No surprise there.
1) I want to log a user in and set his $_SESSION id to his user ID from a db.
2) I suck so much at PDO it's not even funny, I can't figure out what function to use to log the user in. If the number or rows is always 0, clearly the Username or password incorrect will appear all the time.
Try this :
try
{
$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
$bdd = new PDO('mysql:host='.$host.';dbname=' . $dbname, $dbuser, $dbpassword, $pdo_options);
$request = $bdd->prepare('SELECT id FROM users WHERE user = :user AND pass = :password');
$request->execute(array('user' => $_POST['user'],
'password' => $_POST['pass']
));
$data = $request->fetch();
if ($data)
{
session_start();
$_SESSION['ID'] = $data['id'];
//you can run other verification here if you want
header('Location: edit.php');
}
else
{
echo 'Username or password incorrect';
}
$requete->closeCursor();
}
catch(Exception $erreur)
{
die('Login error : '.$erreur->getMessage());
}
Hope that helps .