1

I'm trying to create a form that authenticates a username and password that exists in a MySQL database (using UwAmp) It has a database called users and a table called userdetails that has 2 columns Username and Password both contain user and pass respectively as data.

I know I'm not using the best most up to date security methods at the moment (I want to learn that after doing this).

At the moment that page remains on login.php regardless if the details are correct, in both circumstances, everything disappears on the page.

As a side note I may be getting this confused but is there a way of storing a password in a UwAmp database that isn't just plain text. Can I encrypt it?

I have the following PHP file

<?php

    include_once '/includes/db-connect.php'; //Connect to the database
    if(isset($_POST["Username"], $_POST["Password"])) 
    {     

        $name = $_POST["Username"]; 
        $password = $_POST["Password"]; 

        $result1 = mysqli_query($conn, "SELECT Username, Password FROM userdetails WHERE Username = '".$name."' AND  Password = '".$password."'");

        while($row=mysql_fetch_assoc($result1))
        {
           $check_username=$row['Username'];
           $check_password=$row['Password'];
        }

        if($username == $check_username && $password == $check_password) {
           header("Location: welcomePage.html");
        }
        else { 
           echo "No match.";
        }
    }

HTML file

<div class="form_login">


<form name="credentials" action="php/login.php" onsubmit="return validateForm();" method="post">
             Username:<br>
  <input type="text" name="Username" value=""><br>
  Pasword:<br>
  <input type="password" name="Password" value=""><br><br>
  <input type="submit" value="Submit">
</form>


          </div>

errors.

( ! ) Warning: mysql_fetch_assoc() expects parameter 1 to be resource, boolean given in C:\Users\user\Documents\examplePHP\UAMP\UwAmp\www\techTest\php\login.php on line 1

( ! ) Notice: Undefined variable: check_username in C:\Users\user\Documents\examplePHP\UAMP\UwAmp\www\techTest\php\login.php on line 18

5 Answers5

0

The problem is with your query string, as double quote (") can interprete $variables while single quote(') cannot. So remove single quotes in it and keep all query string in double quotes like this;

$result1 = mysqli_query($conn, "SELECT Username, Password FROM userdetails WHERE Username = '".mysqli_escape_string($conn,$name)."' AND Password = '".mysqli_escape_string($conn,$password)"';");

Updated php file:

<?php

    include_once '/includes/db-connect.php'; //Connect to the database
    if(isset($_POST["Username"], $_POST["Password"])) 
    {     

        $name = $_POST["Username"]; 
        $password = $_POST["Password"]; 

        $result1 = mysqli_query($conn, "SELECT Username, Password FROM userdetails WHERE Username = '".mysqli_escape_string($conn,$name)."' AND  Password = '".mysqli_escape_string($conn,$password)"';");

        while($row=mysql_fetch_assoc($result1))
        {
           $check_username=$row['Username'];
           $check_password=$row['Password'];
        }

        if($username == $check_username && $password == $check_password) {
           header("Location: welcomePage.html");
        }
        else { 
           echo "No match.";
        }
    }
Onur A.
  • 3,007
  • 3
  • 22
  • 37
  • I seem to be getting the following. ( ! ) Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in C:\Users\user\Documents\examplePHP\UAMP\UwAmp\www\techTest\php\login.php on line 14 –  Mar 11 '18 at 00:39
  • do you have any data in your DB? – Onur A. Mar 11 '18 at 00:40
  • yea i have 'user' and 'pass' in the respective columns –  Mar 11 '18 at 00:41
  • this is generally happens when your result is not a result (but a "false" instead). probably values in your variables cause some syntax error in the query, I've updated my answer – Onur A. Mar 11 '18 at 00:51
  • I was getting a syntax error on fixing it I'm still getting the same errors as before. Not too sure what to do –  Mar 11 '18 at 01:11
  • i posted it in my OP. just at the bottom –  Mar 11 '18 at 01:19
0

I would then refer you to the PHP doc on the hash() call

http://php.net/manual/en/function.hash.php

You can try any number of hash encrypts to see which one works best for you. You are correct by saying that md5() is not considered secure enough by modern industry standards.

Otherwise there are some libraries on gitHub that might work as well. But... they may not work.

Hope that helps.

S. Edward
  • 54
  • 2
0

As an a simple unsecured key it would be.

$password = $_POST['password'];

$encrypted_password = hash(-hash_algorith-, $password);

Then insert into SQL or check for validity

-Hope that helps

S. Edward
  • 54
  • 2
0

Short notes first:

  • The warning mysql_fetch_assoc() expects parameter 1 to be resource, boolean given ... was probably raised because mysqli_query returned FALSE - the value used to signalize a failure - instead of a mysqli_result (see this). Why you have this situation, it's up to you to find out. I didn't saw any inadvertence which might have produced it.
  • The notice Undefined variable: check_username ... is raised in the case when no record is found in the db table. In that case, the variable definitions and the values assignation inside of while statement don't take place. Therefore, outside of while statement the variables $check_username and $check_password are "recognized" as not defined.
  • Don't forget to call exit() after the redirectioning code, e.g. after sending the Location response header.

Now, your first big problem is, that you don't use any prepared statements in order to avoid SQL injection. So, instead of mysqli_query, you should definitely use the functions involved in preparing an sql statement - in this case yours - and injecting the values for eventual parameter markers found in it.

The second big problem would be, indeed, if you would decide to save the password in clear text, or in a not secure form - like md5. The password should be strongly encrypted. For this task I would recommend you to use the password_hash function - either with the PASSWORD_BCRYPT option (a constant defining the Blowfish hashing algorithm), or with the PASSWORD_ARGON2I option (constant defining the Argon2 hashing algorithm and introduced as of PHP 7.2.0). You should thoroughly read the documentation of password_hash and of the used constants. You might maybe want to read this post too.

I wrote a code version below, implementing the two points above, in the hope that it will bring more clarity. I used the object-oriented mysqli library (instead of the procedural one) and my naming/coding conventions though (inclusive for the db table) - so, as I would apply them in my project. It also contains a credentials validation part on the server-side. A required step, actually.

In principle, before creating a login.php code, you should create a page responsible with saving user credentials in the db table. In that page (create-user.php for example), for the given password a password hash will be created (using the password_hash function) and saved. The hash will be a string of minimum 60 aleatory characters. The relevant page code would look like this:

//...

$username = $_POST['username'];
$password = $_POST['password'];

// Create a hash from the posted password.
$passwordHash = password_hash($password, PASSWORD_BCRYPT);

$sql = 'INSERT INTO user_credentials (username, password) VALUES (?, ?)';

$statement = $connection->prepare($sql);
$statement->bind_param('ss', $username, $passwordHash);
$statement->execute();

//...

But, in order to shorten the task for now, you can create in PHP a password hash from the value pass and copy and save it manually, along with the user value:

// Create a hash from the "pass" value.
$passwordHash = password_hash('pass', PASSWORD_BCRYPT);
echo $passwordHash;

Suggestion: for applying error/exception handling you could take a look at this and this tutorial articles.

At last, here is the login page, the db connection code, the table structure and the file system structure that I used:

login.php

<?php
/* Don't use include_once to include the connection page! */
require 'includes/connection.php';

// Operations upon form submission.
if (isset($_POST['submit'])) {
    // Validate username.
    if (!isset($_POST['username']) || empty($_POST['username'])) {
        $errors[] = 'Please provide the username.';
    } /* Other validations here using "else if". For example on username length. */

    // Validate password.
    if (!isset($_POST['password']) || empty($_POST['password'])) {
        $errors[] = 'Please provide the password.';
    } /* Other validations here using "else if". For example on password length. */

    if (!isset($errors)) { // No errors.
        // Get posted credentials.
        $username = $_POST['username'];
        $password = $_POST['password'];

        /*
         * The SQL statement to be prepared. Notice the so-called markers, 
         * e.g. the "?" signs. They will be replaced later with the 
         * corresponding values when using mysqli_stmt::bind_param.
         * 
         * @link http://php.net/manual/en/mysqli.prepare.php
         */
        $sql = 'SELECT username, password 
                FROM user_credentials 
                WHERE username = ? 
                LIMIT 1';

        /*
         * Prepare the SQL statement for execution - ONLY ONCE.
         * 
         * @link http://php.net/manual/en/mysqli.prepare.php
         */
        $statement = $connection->prepare($sql);

        /*
         * Bind variables for the parameter markers (?) in the 
         * SQL statement that was passed to prepare(). The first 
         * argument of bind_param() is a string that contains one 
         * or more characters which specify the types for the 
         * corresponding bind variables.
         * 
         * @link http://php.net/manual/en/mysqli-stmt.bind-param.php
         */
        $statement->bind_param('s', $username);

        /*
         * Execute the prepared SQL statement.
         * When executed any parameter markers which exist will 
         * automatically be replaced with the appropriate data.
         * 
         * @link http://php.net/manual/en/mysqli-stmt.execute.php
         */
        $statement->execute();

        /*
         * Get the result set from the prepared statement.
         * 
         * NOTA BENE:
         * Available only with mysqlnd ("MySQL Native Driver")! If this 
         * is not installed, then uncomment "extension=php_mysqli_mysqlnd.dll" in 
         * PHP config file (php.ini) and restart web server (I assume Apache) and 
         * mysql service. Or use the following functions instead:
         * mysqli_stmt::store_result + mysqli_stmt::bind_result + mysqli_stmt::fetch.
         * 
         * @link http://php.net/manual/en/mysqli-stmt.get-result.php
         * @link https://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
         */
        $result = $statement->get_result();

        /*
         * Fetch the credentials into an associative array.
         * If no record is found, the operation returns NULL.
         */
        $credentials = $result->fetch_array(MYSQLI_ASSOC);

        /*
         * Free the memory associated with the result. You should 
         * always free your result when it is not needed anymore.
         * 
         * @link http://php.net/manual/en/mysqli-result.free.php
         */
        $result->close();

        /*
         * Close the prepared statement. It also deallocates the statement handle.
         * If the statement has pending or unread results, it cancels them 
         * so that the next query can be executed.
         * 
         * @link http://php.net/manual/en/mysqli-stmt.close.php
         */
        $statement->close();

        /*
         * Close the previously opened database connection. Not really needed, 
         * because PHP closes the connection after script processing finishes.
         * 
         * @link http://php.net/manual/en/mysqli.close.php
         */
        $connection->close();

        if (isset($credentials) && $credentials) { // Record found.
            $fetchedUsername = $credentials['username'];
            $fetchedPasswordHash = $credentials['password'];

            /*
             * Compare the posted username with the one saved in db and the posted
             * password with the password hash saved in db using password_hash.
             * 
             * @link https://secure.php.net/manual/en/function.password-verify.php
             * @link https://secure.php.net/manual/en/function.password-hash.php
             */
            if (
                    $username === $fetchedUsername &&
                    password_verify($password, $fetchedPasswordHash)
            ) {
                header('Location: welcome.html');
                exit();
            } else {
                $errors[] = 'Invalid credentials. Please try again.';
            }
        } else {
            $errors[] = 'No credentials found for the given user.';
        }
    }
}

echo '<pre>' . print_r(password_hash('pass', PASSWORD_BCRYPT), TRUE) . '</pre>';
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
        <meta charset="UTF-8" />
        <!-- The above 3 meta tags must come first in the head -->

        <title>Demo - Login</title>

        <script src="https://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>

        <script type="text/javascript">
            $(document).ready(function () {
                $('#username').focus();
            });

            function validateForm() {
                return true;
            }
        </script>

        <style type="text/css">
            body {
                padding: 30px;
            }

            label {
                display: block;
                font-weight: 400;
            }

            input[type="text"],
            input[type="password"] {
                display: block;
                margin-bottom: 20px;
            }

            button {
                display: block;
                padding: 7px 10px;
                background-color: #8daf15;
                color: #fff;
                border: none;
            }

            .messages {
                margin-bottom: 20px;
            }

            .messages .error {
                color: #c00;
            }
        </style>
    </head>
    <body>

        <div class="messages">
            <?php
            if (isset($errors)) {
                foreach ($errors as $error) {
                    ?>
                    <div class="error">
                        <?php echo $error; ?>
                    </div>
                    <?php
                }
            }
            ?>
        </div>

        <div class="form_login">
            <form name="credentials" action="" method="post" onsubmit="return validateForm();">
                <label for="username">Username:</label>
                <input type="text" id="username" name="username" value="<?php echo isset($username) ? $username : ''; ?>">

                <label for="password">Password:</label>
                <input type="password" id="password" name="password" value="<?php echo isset($password) ? $password : ''; ?>">

                <button type="submit" name="submit" value="submit">
                    Submit
                </button>
            </form>
        </div>

    </body>
</html>

includes/connection.php

<?php

// Db configs.
define('HOST', 'localhost');
define('PORT', 3306);
define('DATABASE', 'users');
define('USERNAME', 'youruser');
define('PASSWORD', 'yourpass');

/*
 * Enable internal report functions. This enables the exception handling, 
 * e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions 
 * (mysqli_sql_exception).
 * 
 * MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
 * MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings. 
 * 
 * @link http://php.net/manual/en/class.mysqli-driver.php
 * @link http://php.net/manual/en/mysqli-driver.report-mode.php
 * @link http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

/*
 * Create a new db connection.
 * 
 * @see http://php.net/manual/en/mysqli.construct.php
 */
$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE, PORT);

Create table syntax

CREATE TABLE `user_credentials` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

File system structure

includes
    connection.php
login.php
welcome.html
PajuranCodes
  • 303
  • 3
  • 12
  • 43
  • thankyou so much the comments alone a gold mine of clarity and learning. –  Mar 11 '18 at 05:10
-2

Your code looks solid. I would suggest this to add the encryption.

$password = $_POST[$password];
$password = md5($password);

That should get you where you need to go.

Hope that helps.

S. Edward
  • 54
  • 2
  • Md5 is not considered strong enough. – Tim Morton Mar 11 '18 at 00:30
  • $_POST[$password]; ? how do you get post value with password value as key? – Onur A. Mar 11 '18 at 00:42
  • Honesty. serializing it and throwing it through an AJAX call is your most secure method because you can send it as text or JSON or a few other things. However at that point you are setting up an API of sorts. For a simple login you need to use a straight up HTML form that does . As long as it is an https:// secured page then you'll be fine. – S. Edward Mar 11 '18 at 01:00
  • No, the statement `$password = $_POST[$password];` is logically wrong. if your input is as you mentioned, then you should fetch it like this `$password = $_POST["password"];` (beware of double quotes and lack of question mark) – Onur A. Mar 11 '18 at 01:05
  • true .in fact I would go farther to say if (isset($_POST['"password"])) { $password = $_POST["password"]; } – S. Edward Mar 11 '18 at 01:08