phppassword-protection

Password safety in PHP


I primarily develop HTML/CSS web-pages, and I'm working on a webpage where the users need to have a page password protected from prying eyes. The page would just be for posting non-confidential information, such as private-member events, and scheduling. I know the basics of PHP, and would like to use that, but I'm concerned about safety. The page will have multiple users, but it only needs one password which would be used by all the users. It's also a fairly low-traffic site, so for the situation it doesn't need to be 100% secure, but I would like it to be as secure as possible without too much hassle.

So far I have a login-page that comes up when the user tries to access the member-page, with a password input field, which posts the result to a page called (example name) verifypassword.php

This file looks something like this:

$password = ("mypass");

$passresult = $_POST["password"];
$passresult = strip_tags($passresult);
$passresult = htmlspecialchars($passresult);

if ($passresult != $password) {
die("Invalid password.");
}

elseif ($passresult == &password) {
setcookie("mycookie");
header("location: member-page.php");
}

else {
die("Unknown Error")
}

Then, at the top of the member page, I have some lines of PHP code as follows:

$userloggedin = $_COOKIE["mycookie"];

if (!isset ($userloggedin)) {
die("Please log in to view this page");
}

The files and values themselves are hidden via the die function if the user isn't logged in, but the password and cookie are still being transferred across the server. I've tried to read up on salting and hashing a password value, but unfamiliar with this kind of thing. How should I be doing this? Are there any tutorials or resources I can read? I tried looking on Google, php.net, and of course here on stackoverflow, but I couldn't find anything that dealt with passwords other than creating a database to store multiple user-generated passwords, which isn't what I need.

I'm currently using WAMPP.


Solution

  • The top line of your code, if you want to follow best practice, should look like this:

    $hash = '$2y$10$zRg5l/v9gzD/aICnp/GUlu/rFv/0ZNvxX/A5v86zjepZmuRWWL6IG';
    

    Notice that we're storing a hash instead of the password in plain text. These hashes are generated in the following manner:

    password_hash("test", PASSWORD_DEFAULT);
    

    Why are we doing this? Because if your database (or code, in this case) is accessed somehow, then you don't want your passwords to also be stolen. The built in password handling functions mitigate this as much as possible.

    In terms of checking the password, you have to make your peace that the user will have to send the password over the internet one way or another! If this is a big concern for you, you can use SSL to mitigate this - it is best practice to always use SSL for at least authentication. This means that if someone intercepts the connection between your user and your website, they will only be able to see encrypted data. Anyway, you would check it as follows when it arrives:

    // Assuming single password:
    if ( password_verify( $_POST['password'], $hash ) ) {
        // correct! 
        // the plain text in $_POST['password'] is the same as the plain text used to generate $hash
    }
    

    Okay, so, next thing. Cookies are sent between the browser and the server as a header. These can be set arbitrarily by the client. So if you rely on a cookie such as $_COOKIE['mycookie'] to authenticate users, then someone could just send a manually-crafted Cookie header to imitate the effect of being logged in. The solution to this particular problem is to use sessions. At the top of every script, you run session_start() which sets its own cookie. This cookie does not contain any information, just a randomly generated unique ID. PHP stores information and associates it to that ID (by means of a file in the temp folder) - but at no point is the client itself able to see what that information actually is - or change it.

    To add information to the session you put it in the $_SESSION superglobal as follows:

    $_SESSION['logged_in'] = password_verify( $_POST['password'], $hash );
    

    password_verify will return true if the password matched or false otherwise, so you can rely on this to set the boolean properly.

    So you can rewrite your code as follows for login.php:

    session_start();
    
    $hash = '$2y$10$zRg5l/v9gzD/aICnp/GUlu/rFv/0ZNvxX/A5v86zjepZmuRWWL6IG';
    
    if ( isset($_POST['password']) ) {
        // Assuming single password:
        if ( password_verify( $_POST['password'], $hash ) ) {
            // correct!
            header('Location: /member-page.php');
        }
    }
    // display login form
    

    and at the top of the members page:

    session_start();
    
    if (empty($_SESSION['logged_in'])) { // checks if it's set and if it's false
        die("Please log in to view this page.");
        header('Location: /login.php');
    }
    

    n.b. I rewrote my answer because I realised it didn't answer many of your questions very well :)