PHP 8.0.7 password_verify terminates with error - php

I'm making a dummy login page for a school project, and I'm using a hardcoded login for testing.
However, when I execute the following page:
<!DOCTYPE html>
<html>
<body>
<?php
$email = $password = "";
$loginErr = $loginSuccess = "";
// Dummy login to replace the database
$correctEmail = htmlspecialchars("abc123#gmail.com");
$correctPassword =
"\$2y\$10\$Ul2c6wZYxmO9MCJEnySdT.VnoRz7gAFOGVrAEOAhTFBM/5mp81Xl2";
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
$email = htmlspecialchars($_POST["email"]);
$password = htmlspecialchars($_POST["password"]);
echo gettype($password);
echo gettype($correctPassword);
echo password_verify($password, $correctPassword) or die("Something went wrong");
I get the following output:
stringstringSomething went wrong
I get this output regardless of whether I escape-code the dollar signs in the hash.
When I tried to fetch the exception:
try
{
echo password_verify($password, $correctPassword);
}
catch (Exception $e) { echo $e->getMessage();}
it didn't print anything.
php -l returned no syntax errors for either version of the code.
As stated in the title, I'm using PHP 8.0.7, which should support password_verify according to the function's manual page.
Do any of you know how I can get this function working?
EDIT/SOLUTION: I assumed the function wasn't returning because "echo verify_password($password, $correctPassword)" didn't echo a false value. I now know that I have to typecast false values to int if I want them to show up.
Second, I thought that if the hash was of htmlspecialchars([password here]), then using htmlspecialchars($_POST["password"]) would be fine. Removing htmlspecialchars from the equation entirely fixed the issue.

The problem originates from your use of htmlspecialchars(). htmlspecialchars() is used for encoding certain characters that have meaning in HTML before sending them to the browser. It has no place here.
So, working from your code I set this up on my development server:
<!DOCTYPE html>
<html lang="en-GB">
<body>
<?php
$email = $password = "";
$loginErr = $loginSuccess = "";
// Dummy login to replace the database
$correctEmail = "abc123#gmail.com";
$correctPassword =
'$2y$10$PxZQRBaAG81cH1BCJowrxu7RaNnlm1i.Ls0l95ohU9rvsqqZr3guG';
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$email = $_POST["email"];
$password = $_POST["password"];
echo gettype($password);
echo gettype($correctPassword);
echo password_verify($password, $correctPassword) or die("Something went wrong");
} else {
?>
<form method="POST">
<input name="email"><br>
<input name="password" type="password">
<input type="submit" name="submit">
</form>
<?php
}
I've added a basic form for testing and changed the correct password hash to a hash of 'password', and I've removed the references to htmlspecialchars().
It works fine.
If you're using htmlspecialchars() as an attempt to defend against SQL injection, you've chosen the wrong function.
The quick fix would be to change to using mysqli_real_escape_string(). However, this is not considered best practice, and you should look to refactor your code to use prepared statements when no sanitisation is required at all.

Related

How to make a Multi Login User Using PHP?

<?php
ini_set('display_errors', '1');
require_once 'core/init.php';
if(logged_in() === TRUE) {
header('location: dashboard.php');
}
if($_POST) {
$username = $_POST['username'];
$password = $_POST['password'];
if($username == "") {
echo "Username Field is Required <br />";
}
if($password == "") {
echo "Password Field is Required <br />";
}
if($username && $password) {
if(userExists($username) == TRUE) {
$login = login($username, $password);
if($login) {
$userdata = userdata($username);
$_SESSION['id'] = $userdata['id'];
header('location: dashboard.php');
exit();
} else {
echo "Incorrect username/password combination";
}
} else{
echo "Username does not exists";
}
}
} // /if
?>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles1.css">
<script type="text/javascript" src="jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="scripts.js"></script>
<title>Login</title>
</head>
<body class="container">
<div class = "login-box">
<img src = "image/person1.png" class = "avatar">
<h1 id = "login-header">Login</h1>
<form id=registration_form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="POST">
<div>
<label for="username">Username</label>
<input type="text" name="username" id="form_username" autocomplete="off" placeholder="Username" />
<span id="username_error"></span>
</div>
<br />
<div>
<label for="password">Password</label>
<input type="password" name="password" id="form_password" autocomplete="off" placeholder="Password" />
<span id="password_error"></span>
</div>
<br />
<div>
<input type="submit" name="btnLogin" value = "Login">
</div>
Not yet a member? Register
</form>
</body>
</html>
Can somebody help me regarding to my PHP. I'm very new in PHP. My website must have a multi-login user. But I try to do it and I failed. I don't received any error. But the problem is when I press the login button nothing happen. If the user_type is equal to admin I want to link it to adminPanel.php and if user_type is equal to user I want to link it to userPanel.php. Can somebody fix my code below. I really appreciate it.
function login($username, $password) {
global $connect;
$userdata = userdata($username);
if($userdata) {
$makePassword = makePassword($password, $userdata['salt']);
$sql = "SELECT * FROM tbl_user WHERE username = '$username' AND password = '$makePassword'";
$query = $connect->query($sql);
if($query->num_rows == 1) {
$logged_in_user = mysqli_fetch_assoc($query);
if ($logged_in_user['user_type'] == 'admin') {
$_SESSION['user'] = $logged_in_user;
header('location: adminPanel.php');
}else{
$_SESSION['user'] = $logged_in_user;
header('location: userPanel.php');
}
}
}
$connect->close();
// close the database connection
}
Forword
I feel generous tonight...
This may not fix your issue. As I said in the comments, there are many things that can be wrong. Without more information on what is happening, how you do things there is no way to tell.
These are things that are important (things to check)
how you submit the post (the form)
fields could be named wrong, form could be setup wrong etc.
the form action could simply be wrong
the form method could simply be wrong
how you handle that submission
variables could be sent to login() incorrectly, login($password,$username) instead of login($username,$password)
vairables could simply be translated wrong, for example you could have $_POST['user'] insead of $_POST['username']
you could be doing validation checks on input, which may or may not remove data, could be wrong.
how you handle starting the session
you can't use session until you start it
what if any output you have when handling the submission
output before header location will prevent the redirect
header location does not exit the current code scope, stuff after it can run so you should call exit after doing a redirect.
how you connect to the DB
you may have DB error
what if any errors you get, what error reporting do you have
you could have errors your not reporting for any of the above, and many things I didn't mention.
You probably shouldn't roll you own login system until you have a better handle on the security implications ( and other things).
Password/Security
The makePassword function is not included (in your code), but in any case you should use the built in (PHP5.4+) password function. It's much more secure and saves a lot of work:
function makePassword($plaintext){
return password_hash($plaintext, PASSWORD_DEFAULT);
}
This will return a 60 char long hash, but it's recommended to use VARCHAR(255).
It will look something like this in the DB:
//$2y = BCRYPT (default), $10 Cost or iterations (default), that's all I can remember.
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
Then for login (MySqli):
//session_start(); //make sure this is called
function login($username, $password, \mysqli $connect) //use type hinting
{
//can fail because of syntax errors, missing privileges
$stmt = $connect->prepare('SELECT * FROM tbl_user WHERE username = ?') OR die($connect->error);
//can fail because of incorrect number of arguments, invalid types
$stmt->bind_param("s", $username) OR die($stmt->error);
//can fail for various reasons
$stmt->execute() OR die($stmt->error);
$result = $stmt->get_result();
if($result->num_rows == 1) {
$user = $result->fetch_assoc($query);
if(password_verify($password, $user['password'])){
$_SESSION['user'] = $user;
header('location: '.$user['user_type'].'Panel.php');
exit;
}else{
//password error
}
}else{
//username error
}
}
Personally I only use PDO these days. It's been several years sense I used MySqli (so forgive me if I got anything wrong here).
For PDO, this is how I connect with it:
$dsn = 'mysql:dbname=database;host=localhost';
$user = 'user';
$pass = 'pass';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
try{
$PDO = new PDO($dsn, $user, $pass, $options);
}catch(PDOException $e){
//only show end user error codes
die("Error[{$e->getCode()}] connection to DB");
}
The options turn on, Exception error reporting and set the default fetch mode to fetch associative array. With those settings the same thing as above can be done like this:
//session_start(); //make sure this is called
function login($username, $password, \PDO $Pdo) //use type hinting
{
try{
$stmt = $Pdo->prepare('SELECT * FROM tbl_user WHERE username = :username');
$stmt->execute([':username' => $username]);
if($stmt->rowCount()){
$user = $stmt->fetch();
if(password_verify($password, $user['password'])){
$_SESSION['user'] = $user;
header('location: '.$user['user_type'].'Panel.php');
exit;
}else{
//password error, return an error, or throw an exception etc.
}
}else{
//username error
}
}catch(PDOException $e){
//only show end user error codes
die("Database Error[{$e->getCode()}]");
}
}
If you notice it takes around 5 calls to MySqi, and PDO takes only 3 calls. Besides that MySqi is dealing with 3 objects (mysqli, mysqli_stmt, mysqli_result), PDO deals with only 2 (PDO, PDOStatment). Error reporting is also much cleaner.
A few other notes.
use password_hash($plaintext, algo) to create hashes
use password_verify($plaintext, $hash) to check passwords (note plaintext)
use prepared statements
Do not lookup by password, it's not a secure way of verifing 2 hashes are the same (casing, encoding etc...)
use session_start() before using $_SESSION
Do not output anything (not even a single space) before using header
call exit; after using header as it doesn't exit the script it's called in, so it can run code beneath it and produce unexpected results
avoid using global it can be hard to debug your code, instead use dependency injection (pass in the DB connection)
use DRY principals (Dont Repeat Yourself)
And there is probably a bunch of stuff I am forgetting.
UPDATE
Based on the code you added, the part that handles the form submission can be done like this:
<?php
error_reporting(E_ALL); //unclear
ini_set('display_errors', '1');
require_once 'core/init.php';
if(true === logged_in()) { //put constant values on the left
header('location: dashboard.php');
}
if('POST' == $_SERVER['REQUEST_METHOD']){ //put constant values on the left
//ternary condition (shorthand if then)
$username = empty($_POST['username']) ? false : $_POST['username'];
$password = empty($_POST['password']) ? false : $_POST['password'];
//PHP7+ null coalescing can be used instead of above
//$username = $_POST['username'] ?? false;
if(!$username) {
echo "Username Field is Required <br />";
}
if(!$password) {
echo "Password Field is Required <br />";
}
if($username && $password) {
login($username, $password);
//don't forget the connection, if you use the functions without
//it as a global, (which I refuse to use). I once spent a week
//tracking down changes to a global variable in some code I was fixing, never again.
// global $connect;
// login($username, $password, $connect);
}
}
You don't need to do redirects after calling login it's already doing them. You don't need to check if the user exists because you are already checking when fetching there saved password. If you need to know that information there you can either throw exceptions (to much to cover) or you can have the login function return them. In the case that the login is successfule the code will exit before the errors can return.
Summery
My best guess, barring any errors (and assuming the session is started) is that this is happening
form submission, to self
call to login()
everything works, call to header('location: adminPanel.php'); (with no exit)
code returns to the form page (because no exit)
call to header('location: dashboard.php'); And exit();
But that is just a guess, because when yo say "when I press the login button nothing happen" that can mean many things.
One of these days I will put a tutorial for something like this on my website, but it will be more comprehensive.
Anyway, hope it helps you.

How do I check the password?

recently revealed a problem in my login handler. The thing is, that even though the entered password is correct and matches the one in the database, script still sends me to the mistake page.
session_start();
include ("db.php");
if (isset($_POST['login'])) {
$login = $_POST['login'];
$login = stripslashes($login);
$login = htmlspecialchars($login);
$login = trim($login);
if ($login == '') {
unset($login);
}
}
if (isset($_POST['password'])) {
$password=$_POST['password'];
$password = stripslashes($password);
$password = htmlspecialchars($password);
$password = trim($password);
$password = hash("md5",$password);
if ($password =='') {
unset($password);
}
}
if (empty($login) or empty($password))
{
exit (header('location:index.php'));
}
$result = mysql_query("SELECT * FROM users_data WHERE login='$login'");
$row = mysql_fetch_array($result);
if (empty($row['password']))
{
exit (header('location:mistake.php'));
}
else {
if ($row['password']==$password) {
$_SESSION['login']=$row['login'];
$_SESSION['users_id']=$row['users_id'];
header('location:first.php');
}
else {
header('location:mistake.php');
}
}
The HTML form:
<form action="login.php" method="post" class="login">
<label><span>Login:</span>
<input name="login" type="text" size="20" maxlength="100">
</label>
<label><span>Password:</span>
<input name="password" type="password" size="20" maxlength="100">
</label>
<p>
<input type="submit" name="submit" class ="submit" value="Login">
</p>
UPD: Thank you for your answers, finally I've got where the problem was - I just specified not enough length of password values in the database.
First of all why would you store the password in the database without hashing them(e.g. md5).
If you would do that, then there would be no need to process the password and you could just compare the stored md5(password) with the md5 hash of the password posted by the user.
Also w.r.t it is most likely that you are being redirected to the mistake.php page instead of the success.php page because of the encoding.
It would help if you provide us with the password you are using to test the code (assuming you are testing it. ;) ).
Cheers!
EDIT: Please look at better encryption techniques, as suggested by #jayblancard in the comments below.
try to use isset() instead of empty
if (isset($row['password']))
I will just advice you to try to debug your code, mistake DOT php is called in multiple places so use a die("die message") to see which one is being fired.
Since you don't have tests to your code debug output of valid and invalid input and check output.
Once you are satisfied with the inputs and outputs, check if conditions if they are behaving as expected like previously using die condition maybe.
NB: your code is messy look at this to lean basics
Also look at OO programming

problem with form to send entry to mysql database in php

I have three files working on an login app to learn PHP.
This is the connection with DB
<?php
# Connecting database below
$connection = mysqli_connect('localhost','root','','loginapp');
if ($connection) {
# code...
echo "connected";
}
else{
echo "Errorr";
die("Database");
}?>
and here is the html code for the web view
<html>
<head>
<title>Form</title>
</head>
<body>
<h1>Welcome to My Form</h1>
<form class="" action="login_create.php" method="post">
<input type="text" name="name" placeholder="Enter your name here"><br>
<input type="password" name="password" placeholder="Enter Password" value=""><br>
<input type="submit" name="submit" value="submit">
</form>
</body>
</html>
and here is the file where things are going wrong, its not checking the conditions of entries and not putting the data into database what's wrong going there? help please
sometimes it gives
error that "unknown 'sbumit' in the $_POST" and sometimes it don't
doesn't even show any error
but doesn't even do anything
<?php
include "db.php";
if (isset($_POST['submit'])) {
$username = $_POST['name'];
$password = $_POST['password'];
if (isset($username) && isset($password)) {
if (strlen($username) > 10 && strlen($username) < 3) {
echo "Must enter username & pass between 3 & 10";
echo "So that we can forward your request";
}
else {
$query = "INSERT INTO users (username,password) VALUES ('$username','$password')";
$result = mysqli_query($connection,$query);
if(!$result)
{
die('Sorry Query faild'.mysqli_error());
}
}
}
else
{
echo "You haven't wrote anything, write it first";
}
}?>
Habib,
Some guidance for PHP :
$button = isset($_POST["submit"])?$_POST["submit"]:"";
What this line does is apply a value to the $button variable, the first check is that IF isset($var) THEN (indicated with the ? ) apply the value of $var to the $button variable.
The colon : then sets that if the boolean query (true/false) of the IF returns false, then apply the second value instead, in this case an empty string of "".
This is code minimalisation and you should be aware of it but there is little need to use it, especially while learning.
Feedback on your code:
mysqli_error($connection); Your error feedback for MySQLi should include the connection details, as shown here.
replace the $username = $_POST['name'];
$password = $_POST['password'];
if (isset($username) && isset($password)) {
because you want to check not if they're set but if they're not empty, currently they will be set as they're set to the values of $_POST even if they are null (potentially), so replace with:
if(!empty($username) && !empty($password)){
Also note that ! is the negative operator. so above is IF NOT EMPTY.
if (strlen($username) > 10 && strlen($username) < 3) { this is impossible to reach because you're setting if string is longer then 10 AND string is shorter than 3, this is clearly impossible. replace the && with || which is OR rather than AND .
Personally I think that isset($_POST['submit']) is not the best way, instead checking that if($_POST['submit'] == 'submit') confirms the submission of this form from this submit button (the value is the value set in your HTML form).
$query = "INSERT INTO users (username,password) VALUES ('$username','$password')"; This works fine, BUT you really, really need to do some research into SQL injection attacks and SQL security. read How can I prevent SQL injection in PHP? as a start. This is very important to learn at the start of your PHP MySQL learning.
Also research into PDO database connectivity.
Also be aware that your script will not output anything when you have a successful saving of username/password to the database.
As a closer:
Fnally, set up error logging on your page, to give you useful feedback on errors and problems: error_reporting(E_ALL);
ini_set('display_errors', 1); at the very top of your page. Also see How do I get PHP errors to display?
Change your code as follow.
<?php
include "db.php";
$button = isset($_POST["submit"])?$_POST["submit"]:"";
$username = isset($_POST["name"])?$_POST["name"]:"";
$password = isset($_POST["password "])?$_POST["password "]:"";
/*Commetents*/
$button =isset($_POST["submit"])?$_POST["submit"]:"";
is similar to following code:
if(isset($_POST["submit"]))
{
$button = $_POST["submit"];
}
else
{
$button = $_POST["submit"];
}
You know in Php 5.4 , it will present error,if you do not set any value to variable . that is why we used it. If it doesn't get any value it will set it value "".
if($button == "submit") means when someone will press the button submit then $_POST['submit'] value will be submit which you define in the submit button value.
if($button == "submit")
{
if($username=="" or $password=="")
{
$error ="Username & Password can't be blank";
}
elseif(strlen($username)<3 or strlen($username) > 10 )
{
$error ="Must enter username & pass between 3 & 10";
}
else
{
$query = "INSERT INTO users (username,password) VALUES('$username','$password')";
mysqli_query($connection,$query) or die(mysqli_error());
}
}
echo $error;
Hope it will help you .

Not redirecting on successful login

I have completed a login form and it works 100% on my WAMP server. However when I run it on a live server everything works 100%, apart from when I log in it does not redirect my page to the page it should (just displays a blank HTML page). It is however logged in, because if I enter the url of the page it should go, it displays like it should. The path to the file is correct. I hope my problem is clear. Here is the code for my login form:
<?php
include_once "includes/scripts.php";
session_start();
include_once ("includes/connect.php");
if(isset($_SESSION['logged_in'])) {
header('location: admin_cms.php');
exit();
} else {
if(isset($_POST['username'], $_POST['password'])) {
$username = $_POST['username'];
$password = md5($_POST['password']);
if(empty($username) or empty($password)) {
$error = '<p>NOTE: Fields are blank</p>';
} else {
$query = $pdo->prepare("SELECT * FROM users WHERE user_name = ? AND user_password =?");
$query->bindValue(1, $username);
$query->bindValue(2, $password);
$query->execute();
$num = $query->rowCount();
if($num == 1) {
$_SESSION['logged_in'] = true;
header('location: admin_cms.php');
exit();
} else {
$error = "<p>NOTE: The username or password is incorrect</p>";
}
}
}
?>
<div id="login_container">
<br><img src="images/camelhorst_logo_full.png" style="margin-top:38px;">
<h1>LOGIN<img src="images/three_column_grid_line.png" alt="line"></h1>
<form acton = "admin.php" method="post" autocompleate="off">
<label>Username:</label>
<input type="text" name="username" placeholder="Your Username" required autocomplete="off">
<label>Password:</label>
<input type="password" name="password" placeholder="Your Password" required autocomplete="off">
<input type="submit" value="Login" name="submit_login">
</form>
<?php
if(isset($error)) {
echo $error;
}
?>
<p id="copyright_admin"> © CAMELHORSE CREATIVE STUDIO 2013 </p>
</div><!--login_container-->
<?php
}
?>
</body>
</html>
Firstly, the
session_start()
must be at the very top of the page. There can be nothing, no whitespace before it.
Secondly,
if (empty($username) or empty($password)){
needs to be replaced with this
if (empty($username) || empty($password)){
Try that and see if it works
Also, this is a bit off topic and I'm sure that it's not what's causing your problem, but md5() is very outdated. Try using
sha1();
for encryption instead. sha1() is also a bit old, but it's better than md5().
This too, is kind of off topic. But, it seems notable. You have
if(isset($_POST['username'], $_POST['password'])) {
$username = $_POST['username'];
$password = md5($_POST['password']);
if(empty($username) or empty($password)){
$error = '<p>NOTE: Fields are blank</p>';
}
By default, md5 returns a 32 character hex number even if the value of what's being encrypted is empty. So, the condition
empty($password)
is kind of redundant. What's better to have is this:
if(isset($_POST['username'], $_POST['password'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$pass_enc = md5($_POST['password']);
if(empty($username) || empty($password)){
$error = '<p>NOTE: Fields are blank</p>';
}
change redirection to this.
echo "<script>window.location='admin_cms.php'<script>";
Most times, when your header() redirection fails, it is because there has been previous output (even a whitespace matters here), so you may need to be sure there has been no previous output on the file or any included files.
<?php include_once "includes/scripts.php"; ?>
include_once ("includes/connect.php");
NB: Any space outside the <?php ?> tags is considered output.
E.g.
<?php ...some php code... '
//space below causes output to be written to html
?>
<?php
...more php code here...
?>
Iqbal Malik is right. you should use
echo "window.location='admin_cms.php'";
for the redirection however if you want to keep the header() thing you must put
ob_start()
on top of the page, right under
session_start()
it will work like a charm.
edit:
About the md5 / sha1 thing, Ijust started using:
hash("sha512", md5($password))
for my password encryption.

login fails with correct info using PDO

I converted my login page to use PDO but now it's not working. I've run through all kinds of code examples and I can't figure out where I'm going wrong. This looks perfect to me. Also error reporting is fully enabled and yet I don't get any errors. I just get the browser error for the page being "incorrectly configured". FYI, this is a SQL db
//Code
<?php
require ("../Android/connect_db.php");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$query_unpw = $db->prepare("
SELECT member_mast.company_name
FROM member_mast
WHERE username = ?
AND password = ?
");
//$username = $_POST['username'];
//$password = $_POST['password'];
$username = 'abc';
$password = 'abc';
$name = "name";
$query_unpw->bindValue(1, $username, PDO::PARAM_STR);
$query_unpw->bindValue(2, $password, PDO::PARAM_STR);
$query_unpw->execute();
$count = $query_unpw->rowCount();
if ($count > 0) {
while ($row = $query_unpw->$fetch(PDO::FETCH_ASSOC)) {
$name = $row['company_name'];
}
echo $name;
} else {
echo "Username/Password is invalid";
}
} catch(PDOException $e) {
die($e->getMessage());
}
?>
Now the only thing I've been able to figure out after commenting out different pieces of code is that if I comment out the username and password, like this
//$username = 'abc';
//$password = 'abc';
Then the page loads and just gives me my else echo of "Username/Password is invalid". However I don't think I'm using them wrong and I know they are correct. So the obvious question is am I blind, what's wrong here? The bonus question is, since I will be using _POST for these variables when this works, am I properly sanitizing the user inputs? Still really new to PDO and I want to make sure I'm doing this right. Thanks for the help!
Problem is here:
$query_unpw->$fetch
It must be:
$query_unpw->fetch()
It's a method, so skip that $ sign.
I suggest you to use ini_set('display_errors', "On") while developing.

Categories