5

Another night, another question!

I have created a log in page which works fine if the passwords are in plain text.

The issue I have is that my sign up form uses password_hash to enter an encrypted password to the table.

My current scripts are below.

Sign Up Script

$password = password_hash($_POST['password'], PASSWORD_DEFAULT);

Log In Script

<?php
session_start();
    if(isset($_POST['email'], $_POST['password'])){
        require('../../../private_html/db_connection/connection.php');
        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $query = $conn->prepare("SELECT * FROM user_accounts WHERE email=:email AND password=:password");
        $query->bindParam(':email', $_POST['email']);
        $query->bindParam(':password', $_POST['password']);
        $query->execute();

        if($row = $query->fetch()){
            $_SESSION['email'] = $row['email'];
            $_SESSION['first_name'] = $row['first_name'];
            header("Location: ../../myaccount/myaccount.php");
        }
        else {header("Location:../../login/login.php ");}
    }

?>

I have a couple of questions on this one:

  1. Where do I put password_verify in my login script?
  2. Instead of having to type in multiple $_SESSION['xxx'] = $row['xxx']; to display the users details on the 'My Account' page, how can I utilise the $results = $stmt->fetch(PDO::FETCH_ASSOC); method that I have read about?

Many thanks in advance,

CyrilWalrus

Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141

2 Answers2

11

Before you read the code, keep in mind that the Fake Registration block would not be in your code, but it is necessary to show you this, end-to-end.

<?php
session_start();
    // Begin Vault
    // credentials from a secure Vault, not hard-coded
    $servername="localhost";
    $dbname="login_system";
    $username="dbUserName";
    $password="dbPassword";
    // End Vault

    // The following two variables would come from your form, naturally
    // as $_POST[]
    $formEmail="jsmith123@gmail.com";
    $ctPassword="¿^?fish╔&®)";  // clear text password

    try {
        #if(isset($_POST['email'], $_POST['password'])){
        #require('../../../private_html/db_connection/connection.php');
        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        // Begin Fake Registration
        //   fake it that user already had password set (from some registration insert routine)
        //   the registration routine had SSL/TLS, safely passing bound parameters.
             $hp=password_hash($ctPassword,PASSWORD_DEFAULT); // hashed password, using 
             $conn->query("delete from user_accounts where email='jsmith123@gmail.com'");
             $conn->query("insert user_accounts(first_name,last_name,email,password) values ('joe','smith','jsmith123@gmail.com','$hp')");
        //   we are done assuming we had a registration for somewhere in your system
        // End Fake Registration

        $query = $conn->prepare("SELECT * FROM user_accounts WHERE email=:email");
        $query->bindParam(':email', $formEmail);
        $query->execute();

        unset($_SESSION['email']);
        unset($_SESSION['first_name']);

        if(($row = $query->fetch()) && (password_verify($ctPassword,$row['password']))){
            $_SESSION['email'] = $row['email'];
            $_SESSION['first_name'] = $row['first_name'];
            //header("Location: ../../myaccount/myaccount.php");
            echo "hurray, you authenticated.<br/>";
        }
        else {
            //header("Location:../../login/login.php ");
            echo "invalid login<br/>";
        }
        #}
    } catch (PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();
        exit();
    }
?>

Browser Output:

hurray, you authenticated.

Note, the password_hash() function utilizes a random salt, as is evident if you run it several times, with the hashed password changing with same clearText input, such as these hashed passwords:

$2y$10$KywNHrGiPaK9JaWvOrc8UORdT8UXe60I2Yvj86NGzdUH1uLITJv/q

$2y$10$vgJnAluvhfdwerIX3pAJ0u2UKi3J.pfvd0vIqAwL0Pjr/A0AVwatW

both of which are the result of subsequent hashings, as mentioned, of the same clear text password. The salt and hash cost are baked into the hashed password and saved. These call all be read about in links below.

From the Manual password_hash and password_verify.

Schema

create table user_accounts
(   id int auto_increment primary key,
    first_name varchar(50) not null,
    last_name varchar(50) not null,
    email varchar(100) not null,
    password varchar(255) not null
);
Drew
  • 24,851
  • 10
  • 43
  • 78
  • Now here's an answer that actually makes "sense". – Funk Forty Niner Sep 14 '15 at 10:05
  • 2
    I can just wonder who gave you that downvote. Your Competitor Shit perhaps? The one who never makes a comment about it perhaps? Because of afraid of being shot down perhaps? You got my upvote anyway. – Funk Forty Niner Sep 14 '15 at 10:13
  • @HawasKaPujaari Not politics per se, but "PR". (Public relations) ;-) – Funk Forty Niner Sep 14 '15 at 12:51
  • Thanks! This worked a treat. Do you know how I could utilise `$results = $stmt->fetch(PDO::FETCH_ASSOC)` in this situation? I have read that I can then put `` rather than having lots of `$_SESSION`. –  Sep 14 '15 at 18:07
  • In this particular situation, we aren't even echoing (**column values**) out via PHP to browser, just trying to establish yay or nay on login. But yes, in general, absolutely don't bloat your SESSION footprint unnecessarily. It impacts PHP performance. – Drew Sep 14 '15 at 18:11
-3
$query = $conn->prepare("SELECT * FROM user_accounts WHERE email=?");
$query->execute([$_POST['email']]);

if($row = $query->fetch() && password_verify($_POST['password'], $row['password'])){
    $_SESSION['user'] = $row;
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 1
    @CyrilWalrus - There are tons of possibilities why your script doesn't work, you should tell us a bit more about _what_ is going wrong. The answer above should get you the idea, first make a query by email, afterwards read the hash from the row and check with `password_verify()`. – martinstoeckli Sep 14 '15 at 07:41
  • @martinstoeckli It shouldn't be up to you to "help" out the OP with this answer. This guy should be the one to help the person to figure out why it's not working and I sincerely doubt that they will be offering any further help. This answer doesn't deserve an upvote; plus it's a drop-in answer which isn't worth crap if you ask me. – Funk Forty Niner Sep 14 '15 at 10:04