-1

When I register, it hashes the password and then puts the username and the hashed password into my local database. Works fine. When I try to login, the username and password don't match any in the local database and it throws me the error message called login=error2 into the url, which I have written for the case if something is wrong in that part of the code. So you should look for error2 in login.php. I assume the problem lies there. I have been stuck on it the entire day and can't get it to work.

p.s. I am a front-end dev and the most complicated frameworks I use are jquery and react, so I am sorry if I may sound stupid regarding php/mysql. I started learning php 3 days ago.

I am using XAMPP localhost at port 80, this is the phpmyadmin sql code I used (database name is pixl_users)

create table user_info ( username varchar(12) not null, password varchar(30), email varchar(30), gender int(1), date datetime not null );

$(document).ready(function () {
  //switch to login form
  $('#switch-to-login').click(function () {
    $('#form-register').hide();
    $('#form-login').show();
  });
  //switch to registration form
  $('#switch-to-signup').click(function () {
    $('#form-login').hide();
    $('#form-register').show();
  });
});

========================================

signup.php file

<?php


if (isset($_POST['register'])) {

  include_once 'db-connect.php';

  $username = mysqli_real_escape_string($conn, $_POST['username']);
  $password = mysqli_real_escape_string($conn, $_POST['password']);

  if ((empty($username) || empty($password)) || $username == "admin" || $username == "Admin") {
    // if fields are empty, send back to index and say error msg
    header("Location: index.php?fields=empty");
    exit();
  } else {
    // check for characters which are not allowed in the registration fields
    if (!preg_match('/^[a-zA-Z0-9_.\s]+$/i', $username) || !preg_match('/^[a-zA-Z0-9_.!\s]+$/i', $password)) {
      header("Location: index.php?fields=invalidcharacters");
      exit();
    } else {
        //check if username is longer than 2 and shorter than 13 characters
        if (strlen($username) > 2 && strlen($username) < 13) {
          // check if username is taken
          $sql = "SELECT * FROM user_info WHERE username='$username'";
          $result = mysqli_query($conn, $sql);
          $resultCheck = mysqli_num_rows($result);

          if ($resultCheck > 0) {
            header("Location: index.php?fields=userTaken");
            exit();
          } else {
            //hashing the password
            $hashedPass = password_hash($password, PASSWORD_DEFAULT);
            //insert the user into the database
            $insert = "INSERT INTO user_info (username, password)
            VALUES ('$username', '$hashedPass')";
            //query it into the database
            mysqli_query($conn, $insert);
            //send user to the main website page
            header("Location: index.php");
          }

        } else {
          echo "Username can't be shorter than 3 characters and longer than 12 characters!";
        }


    }
  }

}
login.php file


<?php

session_start();

if (isset($_POST['login'])) {
  // connect to local database
  include 'db-connect.php';
  // get username and password from inputs
  $username = mysqli_real_escape_string($conn, $_POST['login-username']);
  $password = mysqli_real_escape_string($conn, $_POST['login-password']);

  //check if fields are empty
  if (empty($username) || empty($password)) {
    header("Location: index.php?fields=empty");
    exit();
  } else {
    // put usernames from table into array $resultCheck
    $sql = "SELECT * FROM user_info WHERE username='$username'";
    $result = mysqli_query($conn, $sql);
    $resultCheck = mysqli_num_rows($result);
    // if there is 0 usernames in database throw error
    if ($resultCheck < 1) {
      header("Location: index.php?login=error1");
      exit();
    } else {
      if ($row = mysqli_fetch_assoc($result)) {
        //De-hashing the password
        $hashedPassCheck = password_verify($password, $row['password']);
        if ($hashedPassCheck == false) {
          header("Location: index.php?login=error2");
          exit();
        } elseif ($hashedPassCheck == true) {
          // log in the user
          $_SESSION['user_name'] = $row['username'];
          header("Location: index.php?login=success");
          exit();
        }
      }
    }
  }

} else {
  header("Location: index.php?login=error");
  exit();
}
<?php session_start(); ?>

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>database test</title>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <style>
    body {
      background-color: black;
      color: white;
    }
    
    #form-register {
      display: none;
    }
  </style>
</head>

<body>

  <button id="switch-to-login">switch to login</button>
  <button id="switch-to-signup">switch to signup</button>
  <!-- register -->
  <form id="form-register" action="signup.php" method="POST">
    <input id="inp-username" type="text" name="username" placeholder="choose a name" /><br />
    <input id="inp-password" type="password" name="password" placeholder="choose a password" />
    <button id="btn-register" name="register" type="submit">Register</button>
  </form>
  <!-- login -->
  <form id="form-login" action="login.php" method="POST">
    <input id="inp-username" type="text" name="login-username" placeholder="login name" /><br />
    <input id="inp-password" type="password" name="login-password" placeholder="password" />
    <button id="btn-login" name="login" type="submit">Login</button>
  </form>


  <script src="script.js"></script>
</body>

</html>
O. Jones
  • 103,626
  • 17
  • 118
  • 172
Maere
  • 39
  • 7
  • what is password_verify function ? is that possible to show its source? and remember, you cant decript something hashed. you must compare hashed password with databese value. like `hash($password) === $row['password']` – arikanmstf Oct 18 '17 at 14:24
  • 1
    Please only send relevant code. – Mark Baijens Oct 18 '17 at 14:25
  • 4
    *"p.s. I am a front-end dev..., so I am sorry if I may sound stupid regarding php/mysql. I started learning php 3 days ago."* ... to be fair you're using `mysqli_*` and `password_hash()` / `password_verify()` so you're off to a good start... – CD001 Oct 18 '17 at 14:37
  • 1
    @arikanmstf password_verify should get the password which the user has written into the password input field ($password), ecrypts that password and compares it to the password row in the table. At least that was the idea of it. – Maere Oct 18 '17 at 14:41
  • `mysqli_real_escape_string($conn, $_POST['login-password']);` < you don't want to do that, if there's something in your password that would crap out MySQL it's going to be escaped which will change the password before it goes to `password_verify()` - which means it might not match the value in the database. – CD001 Oct 18 '17 at 14:42
  • 1
    @Maere Also, `password_hash()` does **_not_** "encrypt" anything, stop using that word for it, it is **_hashing_**, which is a completely different thing. – GrumpyCrouton Oct 18 '17 at 14:43
  • 2
    You should also look at [bound parameters](http://php.net/manual/en/mysqli-stmt.bind-param.php) rather than interpolating the variables into the string - it's safer and you don't have to muck about with `mysqli_real_escape_string()` - I'd use [PDO](http://php.net/manual/en/book.pdo.php) over `mysqli` personally, it's cleaner when it comes to using parametrised queries and supports many different database servers. – CD001 Oct 18 '17 at 14:45
  • `var_dump($row['password']);` what does it show? – Funk Forty Niner Oct 18 '17 at 14:49
  • @CD001 That's good to know, thank you -I have removed mysqli_real_escape_string and will later take a look at bound parameters. I'll go over PDO as well. – Maere Oct 18 '17 at 14:56
  • Is your `password` column in your `user_info` table wide enough? The php manual recommends `VARCHAR(255)`. If the column is too narrow the hashed password you stored will get truncated, and that will wipe out any hope of it passing `password_verify()`. – O. Jones Oct 18 '17 at 14:57
  • 1
    @O.Jones That was the whole idea behind [what I asked here...](https://stackoverflow.com/questions/46812405/password-is-failing-to-validate-inside-my-login-php#comment80573159_46812405). ;-) Yet, a minimum of 60 is required. – Funk Forty Niner Oct 18 '17 at 14:58
  • @arikanmstf I've tried to replace the old code with this after fetching the username row from the database, but it just sends me to login.php and keeps me there: if(password_hash($password, PASSWORD_DEFAULT) === $row['password']) { $_SESSION['user_name'] = $row['username']; header("Location: index.php?login=success"); exit(); } – Maere Oct 18 '17 at 14:58
  • I guess my turn should come soon *lol!* – Funk Forty Niner Oct 18 '17 at 14:59
  • `if(password_hash($password, PASSWORD_DEFAULT) === $row['password'])` it doesn't work that way. You need to use `password_verify()`, not hash it again. – Funk Forty Niner Oct 18 '17 at 15:03
  • So... you've been asked as to what the password column's length is; we're still waiting. I won't stay here much longer, so you'll need to continue reading the manuals and the syntax; read "all" of it. I have to move on now, good luck. – Funk Forty Niner Oct 18 '17 at 15:05
  • @Fred-ii-Yeah realized it after I ran that code :D Turns everything is fine, the problem was that I have set varchar of password to 30, updating that to 255 helped fixed the problem here =] Thank you – Maere Oct 18 '17 at 15:06
  • @O.Jones It wasn't wide enough, I've set it to 30. Everything works after settings it to 255. Thank you! – Maere Oct 18 '17 at 15:09
  • @CD001 Thanks for all the info you gave me, it will certainly help me later on – Maere Oct 18 '17 at 15:10
  • 1
    @Maere Lemme echo @CD001's point. GOOD JOB going with `password_hash()`. It's hard to believe how many people on Stack Overflow try to reinvent the wheel on password stuff, and end up inventing a flat tire. – O. Jones Oct 18 '17 at 15:11
  • @Maere - no worries, it can get quite depressing in here seeing how many people get the basics so very wrong; it's quite heartening to see someone who's just starting out with PHP/MySQL heading in the right direction ;) – CD001 Oct 18 '17 at 15:16
  • @Maere I only noticed your comment above by revisiting the question to check its status; you didn't ping me correctly, that's why I never received [this message from you](https://stackoverflow.com/questions/46812405/password-is-failing-to-validate-inside-my-login-php?noredirect=1#comment80573916_46812405), where I had a feeling that's what this was all along. The question is a duplicate and has been marked as such. Had I been given that information sooner, it would have probably been a different story. – Funk Forty Niner Oct 18 '17 at 15:39
  • @Fred-ii- My bad. Surely would be. – Maere Oct 18 '17 at 23:19

1 Answers1

1

If you call $hash = password_hash($newRegistrantPassword, PASSWORD_DEFAULT) more than once, you'll get a different $hash every time even if the password you give it is the same. That's because the function generates a different random hash each time. (If you're curious about why, look up rainbow tables.)

If you store $hash in a database column that doesn't have enough characters in it, you'll truncate it. That's bad. Future proof your application by using VARCHAR(255) for the hashed password.

What do I mean by future proof? The php developers recognize that computers get faster and cybercreeps get smarter and passwords get easier to crack. So they added the password_needs_rehash() function . In future releases of php, they may change the PASSWORD_DEFAULT hash methodology, making hashes harder to crack.

Good password verification code for an application expecting a long life might look like this.

  $valid = password_verify ( $passwordPresentedByUser, $storedHash );
  if ( $valid ) {
    if ( password_needs_rehash ( $storedHash, PASSWORD_DEFAULT ) {
      $newHash = password_hash( $passwordPresentedByUser, PASSWORD_DEFAULT );
      /* UPDATE the user's row in the database to store $newHash */
    }
    /* log the user in, have fun! */
  }
  else {
    /* tell the would-be user the username/password combo is invalid */
  }

To troubleshoot your hashing, try putting these lines of code in your php program, and see what happens:

 $myFakePassword = 'BompSheBomp!Wow';
 $hash = password_hash( $myFakePassword, PASSWORD_DEFAULT );
 var_dump( $hash );
 $valid = password_verify ( $myFakePassword, $hash );
 if ( $valid ) echo 'Hey! It worked!';
 else echo 'WTF? password verify didn't work.';

Then make sure you store the hashed password in your database when you register a new user. When a user tries to log in, make sure you use password_verify to check the stored, hashed, password against the one furnished by your user.

You can verify a hashed password. But you can't unhash it.

O. Jones
  • 103,626
  • 17
  • 118
  • 172