-1

Recently I updated my login system to use password_hash() but it doesn't let my users login, I used to use md5() so as you can probably tell it needed updated badly. So I'll leave the relevant code below and your help will be greatly appreciated

Users.php Code

function recover($mode, $email) {
    $mode = sanitize($mode);
    $email = sanitize($email);

    $user_data = user_data(user_id_from_email($email), 'first_name', 'user_id', 'username', 'email', 'email_code');

    if ($mode == 'password') {
        $generated_password = substr(password_hash(rand(999, 999999), CRYPT_BLOWFISH), 0, 14);
        change_password($user_data['user_id'], $generated_password);

        update_user($user_data['user_id'], array('password_recover' => '1'));

        email($email, 'Your new password', "Hello " . $user_data['first_name'] . ",\n\nWe received a request to recover your account.\n\nYour new password is: " . $generated_password . "\n\n - FGS");
    }
}

function change_password($user_id, $password) {
    $user_id = (int)$user_id;
    $password = password_hash($password, CRYPT_BLOWFISH);

    mysql_query("UPDATE `users` SET `password` = '$password', `password_recover` = 0 WHERE `user_id` = $user_id");
}

function register_user($register_data) {
    array_walk($register_data, 'array_sanitize');
    $register_data['password'] = password_hash($register_data['password'], CRYPT_BLOWFISH);

    $fields = '`' . implode('`, `', array_keys($register_data)) . '`';
    $data = '\'' . implode('\', \'', $register_data) . '\'';

    mysql_query("INSERT INTO `users` ($fields) VALUES ($data)");

    email($register_data['email'], 'Your Account', "Hello " . $register_data['first_name'] . ",\n\nYour account is waiting moderation! Thanks for joining us. All you'll need to now is wait and we'll send you a email when your account has been activated just send a message from your GTA account and let us know that you registered your registration will only be successful if you are part of the FGS Crew if you decide to leave your account will become suspended \n\n- FGS");
}
function login($username, $password) {
    $user_id = user_id_from_username($username);

    $username = sanitize($username);
    $password = password_hash($password, CRYPT_BLOWFISH);

    return mysql_result(mysql_query("SELECT COUNT(`user_id`) FROM `users` WHERE `username` = '$username' AND `password` = '$password'"), 0 == 1) ? $user_id : false;
}

Login.php Code

include ("$_SERVER[DOCUMENT_ROOT]/autoload.php");

logged_in_redirect();

if(isset($_GET['signin'])){
    $errors[] = 'You need to be logged in to do that';
}
if(isset($_GET['relogin'])){
    $errors[] = '<strong>There was a problem - </strong>Please try again, and if the problem persists then please contact ' . $title . '';
}

if (empty($_POST) === false) {
     $username = $_POST['username'];
     $password = $_POST['password'];

    if (empty($username) === true || empty($password) === true){
        $errors[] = 'You need to enter your username and password';
    } else if (user_exists($username) === false) {
        $errors[] = 'That user doesn\'t exist have you registered?';
    } else if (user_active($username) === false) {
        $errors[] = 'Your account is awaiting moderator approval';
    } else {
        $login = login($username, $password);
        if ($login === false) {
            $errors[] = 'Username and/or password combination is incorrect';
        } else if (user_suspended($username) === true) {
            $errors[] = '<strong>Account Suspended - </strong>Your account has been suspended please contact support for more information';
    } else {
            $_SESSION['user_id'] = $login;
            $user_id = $_SESSION['user_id'];
            mysql_query("UPDATE `users` SET `online_now` = '1' WHERE `user_id` = $user_id");
            header("Location: $url");
            exit();
        }
    }
}
}
   <form action="" method="post">
       <h4>Log In</h4>
       <input type="text" name="username" placeholder="Username" class="no-margin">
       <input type="password" name="password" placeholder="Password" class="no-margin">
       <input type="submit" value="Log In" class="btn no-margin">
   </form>

When enter the site once i've fixed the mistake they will be asked to reset their password using the forgot password page i've already done so with the test account and it's still not working

FCG
  • 26
  • 6
  • Are all the user's old passwords in the database still MD5 hashes? – Dave Morrissey Aug 09 '14 at 17:57
  • ctrl-f for md5 in your code brings up no results. Are you trying to compare a blowfish hash to a md5 hash the first time they log in after your change? – Sumurai8 Aug 09 '14 at 17:57
  • @DaveMorrissey my new password has been emailed to me and updated in mySQL but I can't login – FCG Aug 09 '14 at 18:01
  • @Sumurai8 I know I replaced all the md5 strings and I think the errors is in the login function where I try to compare the submitted plain-text password with the stored hash password – FCG Aug 09 '14 at 18:02
  • Please consult the manual pages about the function you are using. http://php.net/manual/en/function.password-hash.php The process is clearly described there (which you have incorrectly implemented) – PeeHaa Aug 09 '14 at 18:53
  • Could I Just Use SHA-512 ? – FCG Aug 09 '14 at 20:20

3 Answers3

1

You got the verification of the hash wrong.

password_hash() generates some random salt, and together with the clear text password creates the hash. This will be different every single time.

You are supposed to find the user in the database, read the stored hash from there, and then use password_verify() to see if the clear text password from the login form leads to the same hash that has been stored in the database.

Bonus points if you then use password_needs_rehash() to check if the hash algorithm or the parameters have improved, and then hash and store the password again. This would allow all your hashes to improve to better hashing once the user logs in after the improvement got rolled out. You cannot do this without having the clear text password, and the only time you have it is when the user logs in.

$_POST['username'] containing the username from the login form
$_POST['password'] containing the password from the login form

SELECT username, hash FROM users WHERE username = 'username' //do all the escaping

$user = mysqli_fetch_assoc(...);
if (password_verify($_POST['password'], $user['hash'])) {
    // user has the correct password
} else {
    // login fail
}
Sven
  • 69,403
  • 10
  • 107
  • 109
  • Could I Just Use SHA-512 ? – FCG Aug 09 '14 at 20:18
  • No. And why? If you want to do it properly, you have to have a random salt, and this has to be added to the password, and this would also be needed from the database. – Sven Aug 09 '14 at 22:25
0

I don't know why you're first getting the userid and then counting the rows and then do something. You should rather just select the row where the username is the same like entered and use password_verify().

function login($username, $password) {
    $username = sanitize($username);
    $sql = mysql_query("SELECT * FROM `users` WHERE `username`='".$username."' LIMIT 1");
    $row = mysql_fetch_array($sql);
    if(password_verify($password, $row['password']) === true) {
        return $row['id'];
    } else {
        return false;
    }
}

PS: Stop using the deprecated mysql_* functions. PHP doesn't support the mysql extension anymore. Take a look at PDO.

edit. Consider using PASSWORD_DEFAULT instead of CRYPT_BLOWFISH (does it even work with that constant?). This way PHP will always use the latest and strongest implemented algorithm.

Charlotte Dunois
  • 4,638
  • 2
  • 20
  • 39
0

Please note that even with a better hash algorithm, your implementation is not terribly secure. This question and this question should explain why, and how to use salts properly.

You should not use the mysql_* family of functions anymore. They are deprecated. Use mysqli_* with prepared queries or PDO instead. See this question for more information.


Your problem seems to be a typo. You are passing 0 == 1 as the second argument of mysql_result(..). You probably want to have the comparisation (== 1) behind the closing ).

Current code:

mysql_result(
  mysql_query( "SELECT COUNT(`user_id`) FROM `users` WHERE `username` = '$username' AND `password` = '$password'" 
  ), 0 == 1
) 
? $user_id : false;

What it probably should be:

mysql_result(
  mysql_query( "SELECT COUNT(`user_id`) FROM `users` WHERE `username` = '$username' AND `password` = '$password'" 
  ), 0
) 
== 1 ? $user_id : false;
Community
  • 1
  • 1
Sumurai8
  • 20,333
  • 11
  • 66
  • 100
  • When I update all the mysql_result, mysql_query etc querys to mysqli_result, mysqli_query, mysqli_* it completely breaks the whole system – FCG Aug 09 '14 at 18:27
  • If you use the mysqli_* family of functions, you need to do it properly. Use prepared queries everywhere. `mysqli` is a totally different library than `mysql`. It might not be that easy to change it. – Sumurai8 Aug 09 '14 at 18:35
  • Could I Just Use SHA-512 ? – FCG Aug 09 '14 at 20:20
  • Use the best algorithm that runs in an acceptable time on your setup. – Sumurai8 Aug 09 '14 at 20:22