PHP Login System

Associate
Joined
14 Nov 2006
Posts
2,057
Location
UK
Hi guys, I've been working on a login system for an assignment and I've hit a bit of a wall. Tried lots of things myself but I can't get it working, hoping someone more experienced could shed some light on it!

I haven't made the registration part yet so I've just inserted a user manually into the database.

I used several tutorials and guides to do what I've done so far, and it works but I want to add password hashing with salt into it as I've read this is much better than just hashing the password on it's own.

My login function looks like this at the moment which works but it would just use the same string appended to every password.

PHP:
function validateUser($username, $password) {
		
$P_SALT = 'qWI-lXh.5V##cx$:)|%]ScM3fk87Iuf-S^Ula>%Qv:jv^mm|O,T_=7I/`)~c@£e=';
		
   $mysql = new mysql();
   $ensure_credentials = $mysql->verifyUsernamePass($username, hash('sha512', $password . $P_SALT));
		
       if($ensure_credentials) {
           $_SESSION['status'] = 'authorized';
	       header("location: index.php");
	} else return "Please enter a correct username and password";		
}

And the database query part:

PHP:
function verifyUsernamePass($username, $password) {
			
$query = "SELECT *
	      FROM admins
	      WHERE username = ? AND password = ?
	      LIMIT 1"; //limit to 1
				
    if($stmt = $this->conn->prepare($query)) {
    $stmt->bind_param('ss', $username, $password);
    $stmt->execute();
			
        if($stmt->fetch()) {
            $stmt->close();
            return true;
        }
    }	
}


I made a small function to generate a random string but I'm not sure how to implement it into what I've already done - I tried storing the salt in the database with the username and password, then modifying the query to get that with the username and password but I just got errors with it.

PHP:
$password = "admin";

function makeSsalt() {
  list($usec, $sec) = explode(' ', microtime());
  return (float) $sec + ((float) $usec * 100000);
}
	mt_srand(makeSalt());
	$randVal = mt_rand();
	
	$newPass = $randVal . $password;
	$encryptPass = hash('sha512', $newPass);

If anyone has any pointers, they would be greatly appreciated! I'm not very experienced with PHP yet. Thanks!
 
The general idea of a salt is to help protect against rainbow table attacks (huge lookup of hashed words). If someone gets your database of username / passwords and they are not salted then they can simply run all your user credentials against the rainbow table to crack any simple ones very quickly.

The salt is there to append a string of random characters to the password that would never appear in a standard rainbow lookup. If you use the same salt for every user then if someone gets hold of the salt and user /pass info, they can simply generate a new rainbow table taking into account the salt.

The same is true for a per user salt but as you can imagine, generating a new table for every single user would be massively time consuming and still not guaranteed to work whereas in the other cases you are probably going to get lots of matches on weak passwords even if some of the stronger ones remain secure. With the per user salt, they can only hit the ones they generate rainbow tables for whereas the single salt for everyone means that they will simply run every user record over with the rainbow table and the weak ones will crack first.

To integrate that into a login system you could do the following.

Save unique salt, username, password to the db. Password is hashed using a reproducible algorithm (not incorporating random chars, timestamps etc)

User tries to login with username and password.

Retrieve account via the username.

Using the same hashing algorithm as when you generated the hashed password, take the salt from the db and the password from the user submitted form and hash them in the same way (same order etc).

If the hash of the user submitted password + salt matches the password you retrieved from the db, the user has entered the correct username password.

Thanks for the information and good post!

I think that's what I tried but I couldn't get it to work, I added a new database field, and inserted the generated salt, and updated the hashed password with it. Altered the query to get that as well - I think that's probably where I was going wrong. I was getting an error related to the extra variable I put in there.

Was something like this if I remember:

function verifyUsernamePass($username, $salt, $password) {

and,

$query = "SELECT *
FROM admins
WHERE username = ? salt = ? AND password = ?
LIMIT 1"; //limit to 1

if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('sss', $username, $salt, $password);
$stmt->execute();


Then I would edit the validate function to match, but I just got errors when trying to login then.

fez has given you some good info, but I sort of question the logic in writing this yourself. Are you not allowed to use a library?

I'm not sure, but I can't see why not, I will ask. Are there any particular ones worth taking a look at? the assignment is for a client so it would be good to present them with something more robust.

I haven't done a right lot of PHP in the past but hopefully getting there!

Thanks guys :)
 
Yeah, that's what I want to do. I'd generate the salt when they register and put it with the password.

I have it setup so when a user enters their username and password into the form, it goes to the validateUser function, which at the moment uses the same salt:

PHP:
function validateUser($username, $password) {
		
    $P_SALT = 'qWI-lXh.5V##cx$:)|%]ScM3fk87Iuf-S^Ula>%Qv:jv^mm|O,T_=7I/`)~c@£e=';
		
    $mysql = new mysql();
    $ensure_credentials = $mysql->verifyUsernamePass($username, hash('sha512', $password . $P_SALT));
		
    if($ensure_credentials) {
	$_SESSION['status'] = 'authorized';
	    header("location: index.php");
    } else return "Please enter a correct username and password";
		
}

Then it goes to mysql.php:

PHP:
<?php

require_once 'includes/constants.php';

class mysql {
	private $conn;
	
	function __construct() {
		$this->conn = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME) or 
					  die('There was a problem connecting to the database.');
	}
	
	function verifyUsernamePass($username, $password) {
				
		$query = "SELECT *
				FROM admins
				WHERE username = ? AND password = ?
				LIMIT 1"; //limit to 1 for security
				
		if($stmt = $this->conn->prepare($query)) {
			$stmt->bind_param('ss', $username, $password); //username and password are both strings
			$stmt->execute();
			
			if($stmt->fetch()) {
				$stmt->close();
				return true;
			}
		}	
	}
}

Thanks for the help so far!
 
If this isn't a uni thing / examination then you should probably be using a library, there may be exceptions where you need to vet every line of code but I very much doubt you're one of them. If it is a uni thing you should ask your professor right away, he'll likely allow it being that he's planning to ship the thing out to a 3rd party.

I was hoping fez or someone else would have answered the go to library, I think it's PHPass, but I haven't written anything new in quite some time. Normally I would recommend a framework too, which will have a login system combined. Again my experience doesn't lend itself to recommendations on this, but you'll want to start with someone popular.

You shouldn't follow my advice if you're quite some way through, but I presume you'd work on user access control in fairly early development so you might want to think about reconsidering using pure PHP.

Are you working on a prototype or the final version of something that's going live?

It is for uni yeah, I will ask when I next seem him. I can't see it being problem if I use some existing system, which would be better for the client (more secure and feature rich etc). I haven't even started thinking about password resets and stuff yet!

All I've done in the login form so far, which gets a user to an admin page (which is pretty much blank at the moment). So it wouldn't be a massive loss to move over I don't think.

He'd probably like it if I did my own, but what I could do is use a library for the main but hand my own one in as well to show that I gave it ago at least.
 
I actually got a fail on my first attempt of what was essentially a PHP module for submitting code which was not to the professors expectations. This was after working as developer (using php) for several years. I like to think the guy was just a **** but thems the breaks.

Ask and be specific, but don't waste your time doing anything you don't need to do either. Thats my advice. :)

Thanks for the advice, I will definitely ask when I see him on Monday!

I'd obviously like to get my own version working (would get more marks too), but I can see the benefits of using a something like PHPass after doing some reading.
 
We've got to meet certain criteria in the whole assignment, the user login part is just one of those. Seen a few people just using what dreamweaver gives you. I think using a library will be okay, but I will make sure before putting effort into integrating one.

Seems to be quite a lot when I google, I have just found another indepth tutorial that I will look at tomorrow which have salts and password resets included. See what I can learn from that!
 
The reason I told you not to bother doing extra work is more to do with you running out of time and getting a worse mark because you miss features, rather than what you're actually learning. By all means fit it all in if you can but make sure you make and meet your priorities.

I know I'm really responding to like 3 quotes back but I'm crap at forums. :P

Yeah of course, I'm going to meet all the requirements, I just want to do a good job of them. What I have meets them, but I wanted to make it more secure with the salts being used, rather than just hashing the password on it's own.

I'm getting going with the other parts today, so I don't spend ages banging my head over the password stuff!
 
Back
Top Bottom