-1

this is my first time posting on stackoverflow for a couple of years, so please excuse me if this isn't the correct posting format.

I'm trying to create a simple php registration and login script using mysqli. I have not yet added prepared statements to protect myself from SQL injection attacks as I want to learn the basics of submitting and receiving data from a mysql database first.

I have created a registration script that uses the password_hash function. This is completely working and is submitting to my mysql database perfectly.

However, i'm having problems with the password_verify function. I cannot get it to seem to work. If i don't use the password_hash or password_verify function in my register.php or login.php, the login works perfectly.

Although when using password_verify and password_hash together i cannot get the code to work.

Here's the code for my login.php:

<?php
    include('database_connect.php');

    if(isset($_POST["submit"])) {
        $email = $_POST['email'];
        $password = $_POST['password'];

        $query = mysqli_query($conn, "SELECT * FROM users WHERE email='$email'");

        $row = mysqli_fetch_array($query); 

        $encrypted_password = $row['password'];

        if($row == 1) {
            if(password_verify($password, $encrypted_password)) {
                session_start();
                $_SESSION['email'] = $email;
                header("Location: index.php");
                exit;
            } else {
                echo "Incorrect email or password";
            }
        } else {
            echo "Email cannot be found, please sign up for an account";
        }
    }
?>

Here is the code for my register.php:

<?php

include('database_connect.php');

if(isset($_POST["submit"])) {

    $firstName = $_POST['firstName'];
    $lastName = $_POST['lastName'];
    $email = $_POST['email'];
    $password = $_POST['password'];
    $confirmPassword = $_POST['confirm_password'];

    $encrypted_password = password_hash($password, PASSWORD_DEFAULT);

    $sql = "INSERT INTO users (firstName, lastName, email, password) VALUES ('$firstName','$lastName', '$email', '$encrypted_password')";

    if ($conn->query($sql)) {
        echo "<span>Account created succesfully, please <a href='login.php'>log in</a></span>";
    } else {
        echo "<span>There was an error, please contact site administrator</span>";
    }
}

?> 

I have removed the registration form validation so that the code is easier to read. If anybody could point me to the right direction or help me out, i would gladly appreciate it.

I'm pretty certain it has something to do with password hash, but i'm not sure and after countless attempts i cannot get it working.

All the best.

Matthew98
  • 53
  • 7
  • Tell us about the settings on your password SQL column, the column must be at least 72 characters long for BCRYPT passwords (longer for Argon) so ensure that it's not snipping the hash – Martin Apr 04 '20 at 16:36
  • As `$row` is the result of `mysqli_num_rows`, you cannot get the password from the database row from it, you need to fetch the data as well. – Nigel Ren Apr 04 '20 at 16:37
  • 2
    There is a lot wrong with this code. – Martin Apr 04 '20 at 16:41
  • Yes my password's SQL column is using varchar(255). – Matthew98 Apr 04 '20 at 16:53
  • @Matthew98 is it `_unicode` character set and collation, and is it UTF-8 (`_utf8mb4`)? – Martin Apr 04 '20 at 16:54
  • @Martin Yes, the Collation reads as 'utf8_unicode_ci' on the password field. – Matthew98 Apr 04 '20 at 16:58
  • @Matthew98 close, but no cigar yet -- it should in a perfect world be `_utf8mb4` [reference](https://stackoverflow.com/a/279279/3536236) – Martin Apr 04 '20 at 16:59
  • Just out of curiosity: what have you tried to debug this problem? Even anything? – Nico Haase Apr 04 '20 at 17:00
  • Do you have any PHP error log outputs? Is all the data correctly sitting in the database table? – Martin Apr 04 '20 at 17:08
  • if all looks correct and there are no errors then try printing both the string given and then the hash from the db: `print password." ::: ".$encrypted_password;` and see what that gives, then you/we can independently check this on another system. Remember, your password might actually be "$password" if you've not reset it again! – Martin Apr 04 '20 at 17:19
  • @Martin all data is sitting in database table correctly. I have changed it to _utf8mb4 now. Everything seems to be working perfectly. – Matthew98 Apr 04 '20 at 17:26
  • I will try printing that, and see what it gives me. – Matthew98 Apr 04 '20 at 17:29

1 Answers1

4

(in no particular order)

1)

   $encrypted_password = password_hash('$password', PASSWORD_DEFAULT);

'$password' is a literal $password, because it is in single quotes PHP ignores the variable identifier ($) and prints it directly, as-is.

So your password value is always going to be "$password" and not the string that you were given in $_POST['password'].

Read about this on the original Q&A

2)

    $row = mysqli_num_rows($query);

This variable is a numeric counter of rows, it is not the data within the rows.

To get the data within the rows you want mysqli_fetch_array($query) (or its similar companions).

So;

$row = mysqli_fetch_array($query); 

This will be an array of data values from the database.

3)

Your code is wide open to SQL Injection attack and is completely unsafe. Yes, you're using password hash; that's a start, but you're not securing your user submitted data.

You should be using either MySQLi or PDO Prepared Statement RIGHT NOW.

4)

Headers should always be followed by die/exit commands to stop PHP continuing to execute script actions before deciding to follow the header() relocation action.

e.g.

header("Location: home.php");
exit;

5)

Whilst you may technically survive this time, on this page, you should be putting session_start(); at the very top of your PHP page, not half way down nestled in an unrelated if statement. this is inconsistent and very poor coding that will come back to bite you in the arse.

6)

Look at number 3 again, above, and absolutely do it!

7)

NEVER TRUST USER DATA. EVER.

So check and verify all values passwed from the <form> are roughly the expected shape. (filter_var($email, filter_validate_email) ;-)


After update to question.

8)

Read your PHP Error Log file. This will save you (and us all) an epic amount of time!

9)

Best practise is that if you're using PASSWORD_BCRYPT or PASSWORD_DEFAULT that you really, really should be manually setting the cost parameter yourself as the default value (10) is far too low. You should be setting it to as high a value as your server can comfortably take (14 as a guideline minimum).

Please view the details on the PHP Password_hash Manual page.

 $encrypted = password_hash($password, PASSWORD_DEFAULT, ['cost' => 15]);
Martin
  • 22,212
  • 11
  • 70
  • 132
  • Thank you Martain, that is extremely helpful! I have amended all those changes but it still doesn't seem to work. I get the output 'Email cannot be found, please sign up for an account' now. I'm aware about the prepared statements and injections attack and just wanted to get the basics down for now, and come back to that once i understand the basics. – Matthew98 Apr 04 '20 at 16:54
  • 2
    @Matthew98 - It would be great if you changed your code so we see all the updates and can help you further! – bestprogrammerintheworld Apr 04 '20 at 16:59
  • @Matthew98 try to set: `if(mysqli_num_rows($query) === 1) {` for that if condition. And as @bestprogrammerintheworld stated, please update your question fully. Thanks. – Martin Apr 04 '20 at 17:01
  • What a answer! Congrats. – Elias Soares Apr 04 '20 at 17:03
  • @EliasSoares thank you. I've just added to it. `:-p` – Martin Apr 04 '20 at 17:11
  • Thank you everyone (especially @Martin), working now! :) Just about to add form validation and prepared statements to stop injection attacks. – Matthew98 Apr 04 '20 at 17:17
  • @Matthew98 great, glad you got it sorted -- I had just now commented more ideas on the question comments! `:-)` – Martin Apr 04 '20 at 17:19