So I'm trying to make a fairly simple login system, but for some reason the hashed password that is being sent to my database is not hashing correctly. I checked my database and the stored password is not what the sha256 hashed with the generated salt appended is not what it's supposed to be. Here's my code for generating the hash that's being uploaded to the database:
<?php
include "connection.php";
//Check Connection
if ($connect->connect_error) {
echo "Failed to connect to server: " . mysqli_connect_error();
}
//Reset all Checks
$username_exists = NULL;
$email_valid = NULL;
$passwords_match = NULL;
$password_acceptable = NULL;
$password_long_enough = NULL;
$password = NULL;
//Prepare Statements
//Check for Username Existing Statement
$check_username_match = $connect->stmt_init();
$sql_check_username = "SELECT id FROM $tablename WHERE username=?";
$check_username_match->prepare($sql_check_username);
$check_username_match->bind_param("s", $username);
//Insert Into Table Statement
$register_query = $connect->stmt_init();
$sql_register = "INSERT INTO $tablename (username, email, password, token, active, level) VALUES (?, ?, ?, ?, ?, ?)";
$register_query->prepare($sql_register);
$register_query->bind_param("sssssi", $username, $email, $hashedpassword, $token, $activated, $level);
//Execute When Form Submitted
if($_SERVER["REQUEST_METHOD"] == "POST") {
$username = mysqli_escape_string($connect, $_POST['username']);
$email = mysqli_escape_string($connect, $_POST['email']);
$password = $_POST['password'];
$confirm_password = $_POST['confirm_password'];
//Check if Username Exists
$check_username_match->execute();
$check_username_match->store_result();
$numrows = $check_username_match->num_rows;
if ($numrows==0){
$username_exists = false;
} else {
$username_exists=true;
}
//Check if Passwords Match
if ($password==$confirm_password){
$passwords_match = true;
} else {
$passwords_match = false;
}
//Check if Email Address is Valid
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$email_valid = true;
} else {
$email_valid = false;
}
//Check if Passwords Contains Special Characters
$uppercase = preg_match('#[A-Z]#', $password);
$lowercase = preg_match('#[a-z]#', $password);
$number = preg_match('#[0-9]#', $password);
//Check if Password is Long Enough
$password_length = strlen($password);
if ($password_length>8){
$password_long_enough = true;
} else {
$password_long_enough = false;
}
//Validate Password
if(!$uppercase || !$lowercase || !$number || !$password_long_enough || $password = '') {
$password_acceptable = false;
} else {
$password_acceptable = true;
}
//Register if all Validations Met
if(!$username_exists && $email_valid && $passwords_match && $password_acceptable){
//$salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
$token = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
$activated="No";
$level = 0;
$hashedpassword = password_hash($password, PASSWORD_DEFAULT);
$register_query->execute();
$message = "Hello, welcome to the site.\r\n\r\nPlease click on the following link to activate your account:\r\nlocalhost/login_system/activate.php?token=".$token;
mail($email, 'Please Activate Your Account', $message);
header("Location: login.php");
}
}
?>
UPDATE: I changed my above code to reflect the changes I made with password_hash. However, the problem still persists.
This is my login php:
<?php
include("connection.php");
session_start();
//Reset Variables
$message = '';
$location = "/login_system/index.php"; //default location to redirect after logging in
$username = '';
$password = '';
//Check to see if user is newly activated; if he is display a welcome message.
if(isset($_GET['activated'])){
if($_GET['activated'] == "true"){
$message = "Thank you for verifying your account. Please login to continue.";
}
}
//Check to see if user is coming from another page; if he is then store that page location to redirect to after logging in.
if(isset($_GET['location'])) {
$location = htmlspecialchars($_GET['location']);
}
echo $location;
//Prepare login check statement
$check_login = $connect->stmt_init();
$sql = "SELECT id, password FROM $tablename WHERE username=?";
$check_login->prepare($sql);
$check_login->bind_param("s", $username);
//Execute Login Check
if($_SERVER["REQUEST_METHOD"] == "POST") {
$username = mysqli_escape_string($connect, $_POST['username']);
$password = $_POST['password'];
$check_login->execute();
$check_login->store_result();
$numrows = $check_login->num_rows;
$check_login->bind_result($id, $match);
$check_login->fetch();
if ($numrows==1 && password_verify($password, $match)) {
$_SESSION['login_user'] = $id;
$goto = "localhost".$location;
header("location: $goto");
$message = "Success!";
} else {
$message="Username or password is not valid."."<br>".$match."<br>";
}
}
$connect->close();
?>
You should just feed the password you want to hash into PHP's password_hash();function. Like so...
$password = $_POST['password'];
$options = [
'cost' => 12,
];
echo password_hash($password, PASSWORD_BCRYPT, $options);
Then when you want to check if the password exists in the database use password_verify(); Like so...
$password = PASSWORD_HERE;
$stored_hash = HASH_HERE;
if (password_verify($password, $stored_hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
Related
I need a second pair of eyes to have a look at my code and tell me what I am missing, as I think I have identified the portion of code that doesn't work, I just don't know why.
Basically I am trying to register a user to a database, in a way that it prevents SQL injection. For the life of me however, it doesn't work. When I deconstruct the code and make it less secure, it works. Anyway, code is here:
//require_once 'sendEmails.php';
session_start();
$username = "";
$email = "";
$user_dob = "";
$user_fname = "";
$user_lname = "";
$user_telephone = "";
$errors = [];
$servername = '';
$login = '';
$password = '';
$DBname = '';
$rows = 0;
$query = "";
$conn = new mysqli($servername, $login, $password, $DBname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
if ($conn) {
echo "Connected successfully";
}
// SIGN UP USER
if (isset($_POST['signup-btn'])) {
if (empty($_POST['username'])) {
$errors['username'] = 'Username required';
}
if (empty($_POST['email'])) {
$errors['email'] = 'Email required';
}
if (empty($_POST['password'])) {
$errors['password'] = 'Password required';
}
if (isset($_POST['password']) && $_POST['password'] !== $_POST['passwordConf']) {
$errors['passwordConf'] = 'The two passwords do not match';
}
if (empty($_POST['dob'])) {
$errors['dob'] = 'Date of birth required';
}
if (empty($_POST['fname'])) {
$errors['fname'] = 'First name required';
}
if (empty($_POST['lname'])) {
$errors['lname'] = 'Last name required';
}
if (empty($_POST['telephone'])) {
$errors['telephone'] = 'Telephone number required';
} //--checks input in browser
//I think it works untill this point...
$token = bin2hex(random_bytes(50)); // generate unique token
$username = $_POST['username'];
$password = password_hash($_POST['password'], PASSWORD_BCRYPT); //encrypt password
$user_dob = $_POST['dob'];
$user_fname = $_POST['fname'];
$user_lname = $_POST['lname'];
$user_telephone = $_POST['telephone'];
$email = $_POST['email'];
//Above assigns inputted values into variables declared at the start
//echo $token, $email; //-- this works
//nl2br() ; // -- line break in php
// Check if email already exists
//$result = $mysqli->query("SELECT * FROM User_tbl WHERE email='$email' LIMIT 1");
$sql = "SELECT * FROM User_tbl WHERE email='$email' LIMIT 1";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > $rows) {
$errors[] = $email;
echo "Email already exists";
}
$errorsInt = count($errors);
echo mysqli_num_rows($result);
echo count($errors);
echo $errorsInt;
if ($errorsInt === $rows) {
$query = "INSERT INTO User_tbl SET token=?, username=?, password=?, user_dob=?, user_fname=?, user_lname=?, user_telephone=?, email=?";
// "INSERT INTO User_tbl VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
echo $query;
//---------------------------------------------------------------------------
$stmt = $conn->prepare($query); //first
$stmt->bind_param('sssissis', $token, $username, $password, $user_dob, $user_fname, $user_lname, $user_telephone, $email);
$result = $stmt->execute();
echo $result;
if ($result) {
$user_id = $stmt->insert_id;
$stmt->close();
$_SESSION['id'] = $user_id;
$_SESSION['username'] = $username;
$_SESSION['email'] = $email;
$_SESSION['verified'] = false;
$_SESSION['message'] = 'You are logged in!';
$_SESSION['type'] = 'alert-success';
header('location: index.php');
} else {
$_SESSION['error_msg'] = "Database error: Could not register user";
}
}
}
The problem I believe starts here:
$stmt = $conn->prepare($query); //first
$stmt->bind_param('sssissis', $token, $username, $password, $user_dob, $user_fname, $user_lname, $user_telephone, $email);
$result = $stmt->execute();
I am trying to improve my security by using password_hash and PDO prepared statements to prevent SQL Injection. I already worked with MySQLi OOP and Procedural. I am trying to shift to PDO and want to learn.
So I created a signup form using PDO which is already working and the encryption of password is working too. But when I logged in even with the correct username and password I can't login.
This is the code I use to hash my password in the sign up form.
$password = $_POST['password'];
$hash = password_hash($password, PASSWORD_DEFAULT);
Then I execute it using prepared statements. So no errors at here everything works fine.
But when I tried to login it won't redirect me to the landing page where it should be.
So here is the code to my login
<?php
session_start();
$host = "localhost";
$username = "root";
$password = "";
$database = "PDOtesting";
$message = "";
try
{
$connect = new PDO("mysql:host=$host; dbname=$database", $username, $password);
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if(isset($_POST["login"]))
{
if(empty($_POST["username"]) || empty($_POST["password"]))
{
$message = '<label>All fields are required</label>';
}
else
{
$query = "SELECT * FROM users WHERE username = :username AND password = :password";
$statement = $connect->prepare($query);
$statement->execute(
array(
'username' => $_POST["username"],
'password' => $_POST["password"]
)
);
$count = $statement->rowCount();
if($count > 0)
{
$_SESSION["username"] = $_POST["username"];
header("location:login_success.php");
}
else
{
$message = '<label>Wrong Data</label>';
}
}
}
}
catch(PDOException $error)
{
$message = $error->getMessage();
}
?>
Should I include also the password_hash function that I included it in the signup and where should I place the code?
Don't try and match the password in the query, select the user, return and then use password_verify on the result.
Update:
<?php
...
try
{
$connect = new PDO("mysql:host=$host; dbname=$database", $username, $password);
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if(isset($_POST["login"]))
{
if(empty($_POST["username"]) || empty($_POST["password"]))
{
$message = '<label>All fields are required</label>';
}
else
{
$query = "SELECT * FROM users WHERE username = :username LIMIT 1";
$statement = $connect->prepare($query);
$statement->execute(
array(
'username' => $_POST["username"]
)
);
$count = $statement->rowCount();
if($count > 0)
{
$result = $statement->fetch();
//check password
if (password_verify($_POST["password"], $result['password'])) {
$_SESSION["username"] = $_POST["username"];
exit(header("location:login_success.php"));
} else {
$message = '<label>Wrong Data</label>';
}
}
else
{
$message = '<label>Wrong Data</label>';
}
}
}
}
catch(PDOException $error)
{
$message = $error->getMessage();
}
?>
Here is what I did to signup, I am using meekrodb class:
session_start();
include "../includes/db.class.php";
if (!empty($_POST))
$username =$_POST["username"];
$pass =$_POST["password"];
$email =$_POST["email"];
$id_number =$_POST["id_number"];
$password = password_hash($pass, PASSWORD_DEFAULT);
$check = DB::query("SELECT * FROM tbs.credentials WHERE username=%s AND email=%s AND id_number=%s", $username, $email, $id_number);
if ($check)
{
echo '
<div class="medium medium-small red-text animated wobble">Account already exist</div>
<script> M.toast({html: \'Account already exists\'})</script>
<p class="medium medium-small teal-text">Click here to reset password</p>
';
} else {
$rows = array(
'username'=>$username,
'password'=>$password,
'email'=>$email,
'id_number'=>$id_number,
);
$validate = DB::insert('credentials', $rows);
if($validate) {
echo
'
<div class="medium medium-small green-text animated rubberBand">Account created</div>
<script> M.toast({html: \'Account created successful\'})</script>
';
}
}
}
For Loging in:
session_start();
include "../includes/db.class.php";
if (!empty([$_POST])) {
$username = $_POST['username'];
$password = $_POST['password'];
$check = DB::query("SELECT * FROM tbs.credentials where username=%s", $username);
if ($check)
{
$check_password= DB::query("SELECT password FROM tbs.credentials WHERE password=%s", $username);
if ($check_password){
password_verify($password, $check_password);
$_SESSION['username'] = $password;
echo "Login";
}
}
}
I am setting up a PHP lost password page for my website (www.qbstaxsubmission.co.uk) and the code for creating a lost password email which is sent to a user is working just fine. However when the user clicks on the email link he arrives at a new password php page. It's the script on this page which produces a error message 'Registration failure in updating recovery key: INSERT' which fires up my styled error page to transfer the user back to my standard login page.
So my problem is I cannot see what's wrong with my new password2.php. Can anyone help with this?
Here's the full new password2.php code:
<?php
ob_start();
include ('config.php');
include ('function.php');
$error_msg = "";
$token = $_GET['token'];
$userID = UserID($email);
$verifytoken = verifytoken($userID, $token);
// Sanitize and validate the data passed in
if (isset($_POST['submit'],$_POST['username'], $_POST['email'], $_POST['p'])) {
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
$new_password = filter_input(INPUT_POST, 'new_password', FILTER_SANITIZE_STRING);
$retype_password = filter_input(INPUT_POST, 'retype_password', FILTER_SANITIZE_STRING);
$id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_STRING);}
$new_password = filter_input(INPUT_POST, 'p', FILTER_SANITIZE_STRING);
if (strlen($new_password) != 128) {
// The hashed pwd should be 128 characters long.
// If it's not, something really odd has happened
$error_msg .= '<p class="error">Invalid password configuration.</p>';
}
$prep_stmt = "SELECT id FROM members WHERE email = ? LIMIT 1";
$stmt = $db ->prepare($prep_stmt);
if ($stmt) {
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
// A user with this email address already exists
$error_msg .= '<p class="error">A user with this email address already exists.</p>';
}
} else {
$error_msg .= '<p class="error">Database error</p>';
}
if($new_password != $retype_password) {
// Create a random salt
$salt = hash('sha512', uniqid(openssl_random_pseudo_bytes(16), TRUE));
// Create salted password
$new_password = hash('sha512', $random_salt . $salt);
}
// Insert the new hashed password into the database
if ($insert_stmt = $db->prepare("UPDATE members SET password = ? WHERE id = ? ")) {
$insert_stmt->bind_param('si', $newpassword, $id);
// Execute the prepared query.
if (!$insert_stmt->execute()) {
header('Location: ../error.php?err=Database Registration failure: INSERT');
}
// Update recovery key
if ($insert_stmt = $db->prepare("UPDATE recovery_keys SET valid = 0 WHERE id = ? AND token = ? "));
$insert_stmt->bind_param('is', $id, $token);
// Execute the prepared query.
if ($insert_stmt->execute())
$msg = 'Your password has changed successfully. Please login with your new password.';
}else
{
header('Location: ../error.php?err=Registration failure in updating recovery key: INSERT'); }
{exit();}
?>
When the code above is run I get a blank page with the the correct token code shown in the site link.
This password2.php page has an include to a functions page which is shown below.
function checkUser($email)
{
global $db;
$query = mysqli_query($db, "SELECT id FROM members WHERE email = '$email'");
if(mysqli_num_rows($query) > 0)
{
return 'true';
}else
{
return 'false'; }
}
function id($email)
{
global $db;
$query = mysqli_query($db, "SELECT id FROM members WHERE email = '$email'");
$row = mysqli_fetch_assoc($query);
return $row['id'];
}
function generateRandomString($length = 25) {
// This function has taken from stackoverflow.com
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return md5($randomString);
}
function send_mail($to, $token)
{
require 'PHPMailer/PHPMailerAutoload.php';
$mail = new PHPMailer;
//$mail->SMTPDebug = 3;
$mail->isSMTP();
$mail->Host = '';
$mail->SMTPAuth = true;
$mail->Username = '';
$mail->Password = '';
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;
$mail->SetFrom = '';
$mail->FromName = '';
$mail->addAddress($to);
$mail->addReplyTo('', 'Reply');
$mail->isHTML(true);
$mail->Subject = 'Company Password Recovery Instruction';
$link = 'x.php?email='.$to.'&token='.$token;
$mail->Body = "<b>Hi</b><br><br>You have just requested a new password for your company account with QBS Tax Submission. <a href='$link' target='_blank'>Click here</a> to reset your password. If you are unable to click the link then copy the hyper link below and paste into your browser to reset your password.<br><i>". $link."</i>";
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
if(!$mail->send()) {
return 'fail';
} else {
return 'success';
}
}
function verifytoken($id, $token)
{
global $db;
$query = mysqli_query($db, "SELECT valid FROM recovery_keys WHERE id = $id AND token = '$token'");
$row = mysqli_fetch_assoc($query);
if(mysqli_num_rows($query) > 0)
{
if($row['valid'] == 1)
{
return 1;
}else
{
return 0;
}
}else
{
return 0;
}
}
function login($email, $password, $mysqli) {
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, email, password, salt
FROM members
WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($id, $username, $db_password, $salt);
$stmt->fetch();
// hash the password with the unique salt.
$password = hash('sha512', $password . $salt);
if ($stmt->num_rows == 1) {
// If the user exists we check if the account is locked
// from too many login attempts
if (checkbrute($id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
// Check if the password in the database matches
// the password the user submitted.
if ($db_password == $password) {
// Password is correct!
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
// XSS protection as we might print this value
$id = preg_replace("/[^0-9]+/", "", $id);
$_SESSION['id'] = $id;
// XSS protection as we might print this value
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password . $user_browser);
// Login successful.
return true;
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
if (!$mysqli->query("INSERT INTO login_attempts(id, time)
VALUES ('$id', '$now')")) {
header("Location: ../error.php?err=Database error: login_attempts");
exit();
}
return false;
}
}
} else {
// No user exists.
return false;
}
} else {
// Could not create a prepared statement
header("Location: ../error.php?err=Database error: cannot prepare statement");
exit();
}
}
function checkbrute($id, $mysqli) {
// Get timestamp of current time
$now = time();
// All login attempts are counted from the past 2 hours.
$valid_attempts = $now - (2 * 60 * 60);
if ($stmt = $mysqli->prepare("SELECT time
FROM login_attempts
WHERE id = ? AND time > '$valid_attempts'")) {
$stmt->bind_param('i', $id);
// Execute the prepared query.
$stmt->execute();
$stmt->store_result();
// If there have been more than 5 failed logins
if ($stmt->num_rows > 5) {
return true;
} else {
return false;
}
} else {
// Could not create a prepared statement
header("Location: ../error.php?err=Database error: cannot prepare statement");
exit();
}
}
function login_check($mysqli) {
// Check if all session variables are set
if (isset($_SESSION['id'], $_SESSION['username'], $_SESSION['login_string'])) {
$id = $_SESSION['id'];
$login_string = $_SESSION['login_string'];
$username = $_SESSION['username'];
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
if ($stmt = $mysqli->prepare("SELECT password
FROM members
WHERE id = ? LIMIT 1")) {
// Bind "$id" to parameter.
$stmt->bind_param('i', $id);
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
if ($stmt->num_rows == 1) {
// If the user exists get variables from result.
$stmt->bind_result($password);
$stmt->fetch();
$login_check = hash('sha512', $password . $user_browser);
if ($login_check == $login_string) {
// Logged In!
return true;
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Could not prepare statement
header("Location: ../error.php?err=Database error: cannot prepare statement");
exit();
}
} else {
// Not logged in
return false;
}
}
function esc_url($url) {
if ('' == $url) {
return $url;
}
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%#$\|*\'()\\x80-\\xff]|i', '', $url);
$strip = array('%0d', '%0a', '%0D', '%0A');
$url = (string) $url;
$count = 1;
while ($count) {
$url = str_replace($strip, '', $url, $count);
}
$url = str_replace(';//', '://', $url);
$url = htmlentities($url);
$url = str_replace('&', '&', $url);
$url = str_replace("'", ''', $url);
if ($url[0] !== '/') {
// We're only interested in relative links from $_SERVER['PHP_SELF']
return '';
} else {
return $url;
}
}
I believ this is where the issue is:
if (! $insert_stmt->execute())
$msg = 'Your password has changed successfully. Please login with your new password.';
}else{..}
if (! $insert_stmt->execute()) this means if the query fails echo that password fails.....
the reason your code always display Registration failure in updating recovery key: INSERT its because you instructed your code that when the query does not fail it must produce that.
And your code all of it is in mess, you need to clean it up.
Thi is how this should look.
if ($insert_stmt = $db->prepare("UPDATE recovery_keys SET valid = 0 WHERE userID = ? AND token = ? "));
$insert_stmt->bind_param('ss', $userID, $token);
// Execute the prepared query.
if ($insert_stmt->execute())
$msg = 'Your password has changed successfully. Please login with your new password.';
}else
{
$msg = "Password doesn't match";
header('Location: ../error.php?err=Registration failure in updating recovery key: INSERT'); }
{exit();}
Edit
Tried to clean up some of the mess in your code. Now this how should look.
<?php
ob_start();
include('config.php');
include('function.php');
$error_msg = "";
$token = $_GET['token'];
$userID = UserID($email);
$verifytoken = verifytoken($userID, $token);
// Sanitize and validate the data passed in
if (isset($_POST['submit'], $_POST['username'], $_POST['email'], $_POST['p'])) {
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
$new_password = filter_input(INPUT_POST, 'new_password', FILTER_SANITIZE_STRING);
$retype_password = filter_input(INPUT_POST, 'retype_password', FILTER_SANITIZE_STRING);
$id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_STRING);
}
$new_password = filter_input(INPUT_POST, 'p', FILTER_SANITIZE_STRING);
if (strlen($password) != 128) {
// The hashed pwd should be 128 characters long.
// If it's not, something really odd has happened
$error_msg .= '<p class="error">Invalid password configuration.</p>';
}
$prep_stmt = "SELECT id FROM members WHERE email = ? LIMIT 1";
$stmt = $db->prepare($prep_stmt);
if ($stmt) {
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
// A user with this email address already exists
$error_msg .= '<p class="error">A user with this email address already exists.</p>';
}
} else {
$error_msg .= '<p class="error">Database error</p>';
}
if ($new_password != $retype_password) {
// Create a random salt
$salt = hash('sha512', uniqid(openssl_random_pseudo_bytes(16), TRUE));
// Create salted password
$new_password = hash('sha512', $random_salt . $salt);
}
// Insert the new hashed password into the database
if ($insert_stmt = $db->prepare("UPDATE members SET password = ? WHERE id = ?")) {
$insert_stmt->bind_param('si', $new_password, $userID);
// Execute the prepared query.
if (!$insert_stmt->execute()) {
header('Location: ../error.php?err=Database Registration failure: INSERT');
exit();
}
// Update recovery key
if ($insert_stmt = $db->prepare("UPDATE recovery_keys SET valid = 0 WHERE userID = ? AND token = ? "));
$insert_stmt->bind_param('is', $userID, $token);
// Execute the prepared query.
if ($insert_stmt->execute())
$msg = 'Your password has changed successfully. Please login with your new password.';
} else {
$msg = "Password doesn't match";
header('Location: ../error.php?err=Registration failure in updating recovery key: INSERT');
exit();
}
?>
Important things you need to learn proper.
Update : here's the link
Prepared statements : link here
password hashing : link here
Your hashing method is very easy php does provide better and secure ways, please follow the links above.
I'm stuck with resetting password in php. I'm using password_hash for register, password_verify for login, everything seemed to work until I had the idea to implement the reset password thing. My plan was to have of course 3 fields:oldPassword, newPassword,confirmNewPassword.
First I check if the oldPassword is in db, if yes than after checking if the 2 new passwords are correct to update in db the newPassword. The problem is that I can update in my db the new hashed password but when I login again it can't recognize the password and can't log in. And I really can't understand why.
Here's my code:
For register (maybe it's useless but anyway)
if ($_POST['actiune'] == 'register') {
$firstname = $_POST['firstName'];
$lastname = $_POST['lastName'];
$email = $_POST['email'];
$_SESSION['username'] = $email;
$password = $_POST['password'];
$hash = password_hash($password, PASSWORD_BCRYPT);
$age = $_POST['age'];
$address = $_POST['address'];
if(addUser($firstname, $lastname, $email, $hash, $age, $address)) {
header("Location: index.php?page=profile");
}
else
die("User didnt add in db.");
}
login:
if($_POST['actiune'] == 'login') {
$email = $_POST['email'];
$password = $_POST['password'];
$pass = getPassword($email);
$verify = password_verify($password, $pass);
if ($verify) {
$_SESSION['username'] = $email;
header("Location: index.php?page=profile");
} else {
header("Location: index.php?page=login&msg=PleaseRegister");
die();
}
}
resetPassword:
if($_POST['actiune'] == 'resetPassword') {
$oldPassword = $_POST['oldPassword'];
$newPassword = $_POST['newPassword'];
$confirmPassword = $_POST["confirmPassword"];
$passwordDb = getPassword($_SESSION['username']);
$verify = password_verify($oldPassword, $passwordDb);
if($verify) {
setPassword($newPassword, $_SESSION['username']);
header("location: index.php?page=profile");
}
}
function setPassword
function setPassword($password, $email) {
include("connectionFile.php");
$hash = password_hash($password, PASSWORD_BCRYPT);
try {
$sql = $conn->prepare("update user set password = '$hash' where email='$email'");
$sql->execute();
} catch(Exception $e) {
echo $e->getMessage();
return false;
}
return true;
}
getPassword function used for login:
function getPassword($email) {
include("connectionFile.php");
$sql = $conn->prepare("select * from user where email='$email'");
$sql->execute();
$result = $sql;
foreach($result as $row) {
$pass= $row['password'];
}
return $pass;
}
As I wrote in comments:
setPassword($newPassword, $_SESSION['username']
You're using the wrong variable in:
function setPassword($password, $email)
...
password_hash($password,
The variable should have been $newPassword and not $password.
Your code failed on your silently since password_hash() did do its job, it just didn't hash the said/wanted variable.
This, and along with my other comments about your being open to an SQL injection.
Halo there,
I have a problem of logging in my registered user, I've hashed the passwords and when I log in my form refuse, So I don't really know whats the problem because the user I registered Directly with sql command can actually login below is my login script...
<?php
include 'db_connect.php';
include 'functions.php';
sec_session_start(); // Our custom secure way of starting a php session.
if(isset($_POST['email'], $_POST['p'])) {
$email = $_POST['email'];
$password = $_POST['p']; // The hashed password.
if(login($email, $password, $mysqli) == true) {
// Login success
echo 'Success: You have been logged in!';
echo 'Close window';
} else {
// Login failed
header('Location: ./login.php?error=1');
}
} else {
// The correct POST variables were not sent to this page.
echo 'Invalid Request';
}
?>
And Below is my login function on the Function.php file
function login($email, $password, $mysqli) {
if ($stmt = $mysqli->prepare(
"SELECT id, username, password, salt
FROM members
WHERE email = ?
LIMIT 1"
)) {
$stmt->bind_param('s', $email);
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($user_id, $username, $db_password, $salt);
$stmt->fetch();
$password = hash('sha512', $password.$salt); // hash the password with the unique salt.
if($stmt->num_rows == 1) {
if(checkbrute($user_id, $mysqli) == true) {
return false;
} else {
if($db_password == $password) {
$ip_address = $_SERVER['REMOTE_ADDR'];
$user_browser = $_SERVER['HTTP_USER_AGENT'];
$user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we might print this value
$_SESSION['user_id'] = $user_id;
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password.$ip_address.$user_browser);
// Login successful.
return true;
} else {
$now = time();
$mysqli->query(
"INSERT INTO login_attempts (user_id, time)
VALUES ('$user_id', '$now')"
);
return false;
}
}
} else {
// No user exists.
return false;
}
}
}
below is how I Register the user to the DB
<?php
include 'db_connect.php';
include 'functions.php';
$password = $_POST['p'];
$username = $_POST['username'];
$email = $_POST['email'];
$random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
$password = hash('sha512', $password.$random_salt);
if ($insert_stmt = $mysqli->prepare(
"INSERT INTO members (username,email,password,salt)
VALUES (?, ?, ?, ?)"
)) {
$insert_stmt->bind_param('ssss', $username, $email, $password, $random_salt);
// Execute the prepared query.
$insert_stmt->execute();
echo 'Member Succesfully added to the Website list';
} else {
echo 'Error couldnt add the user, Try again';
}
?>
I am guessing you have either randomely changed the password somehow, when you sign up---sha512( $password) and login should be the same in order to match it when quering the data---The $Salt is a bit confusing to?
Login
$_POST['password'] = stripslashes($_POST['password']);
$password = mysql_real_escape_string(sha512($_POST['password']));
Signup
$_POST['password'] = stripslashes($_POST['password']);
$password = mysql_real_escape_string(sha512($_POST['password']));