I am attempting to make a more secure log in system. My registration is working fine so its not a connection issue. Just needing a fresh pair of eyes to see if there are any errors that I may be missing, can anyone help please? Thanks!
login.php
session_start();
if (isset($_POST['submit']))
{
$user = $_POST['username'];
$pass = $_POST['password'];
if(!($stmt = $mysqli->prepare("SELECT username, password FROM users WHERE username = ?"))){
echo "Prepare failed: (" . $mysqli->errno . ")" . $mysqli->error;
}
if(!$stmt->bind_param('s', $user)){
echo "Bind failed: (" . $stmt->errno . ")" . $stmt->error;
}
if(!$stmt->execute()){
echo "Execute failed: (" . $stmt->errno .")" . $stmt->error;
}
$userdata = $stmt->get_result();
$row = $userdata->fetch_array(MYSQLI_ASSOC);
$stmt->bind_result($user, $pass);
$stmt->store_result();
if(password_verify($pass, $row['password'])){
$_SESSION['login_user'] = $_POST['username'];
header('Location: profile.php');
exit();
}
}
else{
echo "Login Failed: (" . $stmt->errno .")" . $stmt->error;
}
$stmt->close();
$mysqli->close();
index.php(The login form)
<div id="loginform">
Log in details<br /><br />
<form method="post" action="login.php">
Username:
<input type="text" name="username" />
<br /><br>
Password:
<input type="password" name="password" />
<br /><br>
<input type="submit" name="submit" value="Submit" />
</form>
</div>
You shouldn't use $stmt->errno
and $stmt->error
in the Login Failed
error message. That line is in the else
clause for if (isset($_POST['submit']))
, so it has nothing to do with a MySQL error. I'm not sure why you're ever getting that message, since it should only happen if you go to login.php
without submitting the login form on index.php
.
Since you're using $userdata->fetch_array()
to fetch the row of results from the database, you shouldn't also use $stmt->bind_result()
-- do one or the other. I don't think bind_result()
is doing anything, since you never call $stmt->fetch()
to get a row into those variables.
If you decide to go with bind_result()
, you need to use a different variable for the password, because $pass
contains the password submitted from the form.
You need to check whether a row was returned by the query -- if the user enters an invalid username, it will not. So the password check should be:
if ($row && password_verify($pass, $row['password']) {
...
}
You should then have an else
clause for this that reports that the username or password was invalid. You should not distinguish whether it was the username or password that was wrong, this would be bad for security (it helps a brute-forcer to know that he guessed the username correctly, and just needs to try different passwords).
$stmt->close()
should be inside the if
block.