Jump to content

login class security check


Brazzan

Recommended Posts

I've seen alot of, what I think, good PHP programmers in this forum. I want you to take a look at this login class and other related classes. Im sorry about the commenting..it's in Swedish. But if you know your PHP you should be fine without them...but I admit, it's always helpful with comments. I could'nt be bothered to translate  ;D

 

EDIT: The file settings.php that's included only contains 3 variables. They are just used for some of the error handling and a static salt.

 

demo_register.php

<?php
if(isset($_POST['login']))
{
require_once("system/class/class_login.php"); //Inkluderar klassen login
require_once("system/class/class_accountHandler.php"); //Inkluderar klassen handler
require_once("system/settings/settings.php"); //Inkluderar inställningarna
require_once("db/connect.php"); //Inkluderar anslutningen till databasen

$hndl = new accountHandler(); //Anropar klassen accountHandler
$auth = new login($_POST['username'], $_POST['password'], $static_salt, $usr_min_length, $pwd_min_length, $conn, $hndl); //Anropar klassen login, samt förser __construct med värden
$auth->show_errors(); //Skriver ut errors...optional
}
?>
<form method="post" action="demo_login.php">
Username<br />
<input type="text" name="username" /><br />
Password<br />
<input type="password" name="password" /><br />
<input type="hidden" name="hidden" value="" />
<input type="submit" name="login" value="Login" />
</form>

 

class_login.php

<?php
class login
{
private $static_salt;		//Lagrar ett statiskt salt. Detta salt finns i settings.php
private $conn;				//Lagrar en anslutning till databasen
private $generate;			//Lagrar en anslutning till klassen accountHandler
private $usr_min_length;	//Lagrar minsta antalet tecken som användarnamn får ha. Går att ställa in i settings.php
private $pwd_min_length;	//Lagrar minsta antalet tecken som lösenordet får ha. Går att ställa in i settings.php

private $username;			//Lagrar användarnamnet från formuläret
private $password;			//Lagrar lösenordet från formuläret

private $db_id;				//Lagrar id't från databasen
private $db_username;		//Lagrar användarnamnet från databasen
private $db_password;		//Lagrar lösenordet från databasen
private $db_salt;			//Lagrar saltet från databasen
private $db_x;				//Lagrar x från databasen

private $user_exists;		//True om användaren existerar, annars False
private $user_length;		//True om längden på användarnamnet är acceptabelt, annars False
private $password_length;	//True om längden på lösenordet är acceptabelt, annars False
private $password_match;	//True om lösenordet från formuläret(efter behandling) matchar lösenordet från databasen, annars False

//Metoden autoladdas så fort klassen körs. Den förser klassen med nädvändig information
public function __construct($username, $password, $static_salt, $usr_min_length, $pwd_min_length, $conn, $hndl)
{
	$this->username 		= $username;		//Lagrar användarnamnet från formuläret i klassvariablen username
	$this->password 		= $password;		//Lagrar lösenordet från formuläret i klassvariablen password
	$this->static_salt 		  = $static_salt;		//Lagrar det statiska saltet från settings.php i klassvariablen static_salt
	$this->usr_min_length 	       = $usr_min_length;	//Lagrar en siffra i klassvariablen $usr_min_length som motsvarar antalet tecken ett användarnamn minst ska ha. Värdet finns i settings.php
	$this->pwd_min_length 	= $pwd_min_length;  //Lagrar en siffra i klassvariablen $pwd_min_length som motsvarar antalet tecken ett lösenord minst ska ha. Värdet finns i settings.php
	$this->conn 			= $conn;			//Lagrar anslutningen till databasen i klassvariablen $conn
	$this->generate			= $hndl;			//Lagrar en anslutning till kalssen accountHandler i klassvariablen generate

	$this->check_values();	//Anropar metoden check_values()
	$this->bake_values();	//Anropar metoden bake_values()
	$this->set_session();	//Anropar metoden set_sessiob()
}

/*
####
###
##
#
*/

//Metoden för att kontrollera värden från formuläret
private function check_values()
{
	//Räknar om det angivna användarnamnet förekommer 0 gånger, eller 1 gång. 
	$do= $this->conn->prepare ("SELECT COUNT(id) as antal FROM table WHERE username = :user ");
	$do->bindParam(':user', $this->username, PDO::PARAM_STR);
	$do->execute();
	$obj = $do->fetch(PDO::FETCH_OBJ);

	$db_count = intval($obj->antal); //Innehåller antalet gånger användarnamnet från formuläret förekommer i databasen

	if($db_count < 1){ $this->user_exists = false; 	} //Kontrollerar om användaren inte existerar
	if($db_count > 0){ $this->user_exists = true;	} //Kontrollerar om användare existerar

	if(strlen($this->username) <  $this->usr_min_length) { $this->user_length = false; } //Kontrollerar om längden på användarnamnet inte är acceptabelt
	if(strlen($this->username) >= $this->usr_min_length) { $this->user_length = true;  } //Kontrollerar om längden på användarnamnet acceptabelt

	if(strlen($this->password) <  $this->pwd_min_length) { $this->password_length = false; } //Kontrollerar om längden på lösenordet inte är acceptabelt
	if(strlen($this->password) >= $this->pwd_min_length) { $this->password_length = true;  } //Kontrollerar om längden på lösenordet är acceptabelt

		//En checkpoint som måste passeras
		if($this->user_exists 		== true){
		if($this->user_length  		== true){
		if($this->password_length	== true){

			//Hämtar alla nödvändiga uppgifter från databasen
			$do2 = $this->conn->prepare ("SELECT id, username, password, salt, x FROM table WHERE username = :user ");
			$do2->bindParam(':user', $this->username, PDO::PARAM_STR);
			$do2->execute();
			$obj = $do2->fetch(PDO::FETCH_OBJ);


			$this->db_id		= intval($obj->id); //Lagrar kontots id i klassvariablen $db_id
			$this->db_username 	= $obj->username;	//Lagrar kontots användarnamn i klassvariablen $db_username
			$this->db_password 	= $obj->password;	//Lagrar kontots lösenord i klassvariablen $db_password
			$this->db_salt 		= $obj->salt;		//Lagrar kontots salt i klassvariablen $db_salt
			$this->db_x 		= intval($obj->x);	//Lagrar kontots x i klassvariablen $db_x

			$conn = null; //Stänger anslutningen till databasen
		}
		}
		}		
}

/*
####
###
##
#
*/

//Metod som tar hand om lösenord, salt och x. Lagrar även allt i databasen
private function bake_values()
{
	//Checkpoint som måste passeras
	if($this->user_exists 		== true){
	if($this->user_length 		== true){
	if($this->password_length 	== true){

		//Här tar vi hjälp av en annan klass som tar hand om lösenordet, saltet, x, samt lagrar det i databasen
		$baked_pass = $this->generate->system_password($this->password, $this->static_salt, $this->db_salt, $this->db_x);

		if($baked_pass == $this->db_password) { $this->password_match = true;  } //Kontrollerar om lösenordet från formuläret (efter behandling) matchar lösenordet från databasen
		if($baked_pass !== $this->db_password){ $this->password_match = false; } //Kontrollerar om lösenordet från formuläret (efter behandling) inte matchar lösenordet från databasen	
	}
	}
	}
}

/*
####
###
##
#
*/

//Metod som skriver ut error-meddelande
public function show_errors()
{
	if($this->password_match 	 == false){ $error = "Användarnamn eller lösenord felaktigt!"; } //Om lösenorden inte matchar
	if($this->user_length 		 == false){ $error = "Användarnamn eller lösenord felaktigt!"; } //Om längden på användarnamnet inte är acceptabelt
	if($this->password_length 	 == false){ $error = "Användarnamn eller lösenord felaktigt!"; } //Om längden på lösenordet inte är acceptabelt
	if($this->user_exists		 == false){ $error = "Användarnamn eller lösenord felaktigt!"; } //Om användaren existerar

	echo $error; //Skriver ut meddelandet	
}

/*
####
###
##
#
*/

//Metod som skapar sessionen
private function set_session()
{
	if($this->password_match 	== true){
	if($this->user_length		== true){
	if($this->password_length	== true){
	if($this->user_exists 		== true){

	session_start();

	$PROT = sha1(mt_rand($this->db_x, 100));

	$_SESSION['accID'] 		= $this->db_id;
	$_SESSION['accUSER'] 	= htmlspecialchars($this->db_username);
	$_SESSION['accPROT']	= $PROT;
	$_SESSION['accSEC']		= sha1($_SESSION['accPROT'] . $_SESSION['accID'] . $_SESSION['accUSER'] . strlen($_SESSION['accUSER']));

	}
	}
	}
	}
}

} //Avslutar klassen
?>

 

class_accountHandler.php

<?php
class accountHandler
{
//Metod som tar hand om "skapa konto" processen
public function new_system_account($username, $password, $email, $static_salt, $date, $conn)
{
	$db_x = mt_rand(2, 20); //Genererar ett slumpat tal mellan 2 och 20. Detta tal används för att bestämma hur många gånger salt-loopen ska köras.

	$signs  = "abcdefghijklmnopqrstuvxyz 1234567890!@#£%&=?+-"; //Ur denna variablen hämtas alla tecken för det slumpade saltet
	$length = strlen($signs); //innehåller värdet på antalet tecken som finns i $signs

		//Skapar ett slumpat salt
		for($i=0; $i<$db_x; $i++)
		{
			$rand = mt_rand(0, $length);
			$salt .= substr($signs, $rand, 1);
		}

		$db_salt = sha1($salt.md5($db_x)); //Innehåller det färdiga saltet (dynamiskt)

		$db_pass = $this->system_password($password, $static_salt, $db_salt, $db_x); //Anropar metoden system_password för att behandla lösenordet

		//Sparar kontot i databasen
		$do = $conn->prepare("INSERT INTO table (username, password, salt, x, email, date) VALUES (:user, :pass, :salt, :x, :email, :date)");
		$do->bindParam(':user', $username, PDO::PARAM_STR);
		$do->bindParam(':pass', $db_pass, PDO::PARAM_STR);
		$do->bindParam(':email', $email, PDO::PARAM_STR);
		$do->bindParam(':salt', $db_salt, PDO::PARAM_STR);
		$do->bindParam(':x', $db_x, PDO::PARAM_INT);
		$do->bindParam(':date', $date, PDO::PARAM_STR);
		$do->execute();

		$conn = null; //Stänger anslutningen till databasen.			
}

/*
####
###
##
#
*/

//Metod som behandlar lösenord från formulär
public function system_password($password, $static_salt, $db_salt, $db_x)
{
	$password = md5($password); //Hashar lösenordet med md5

	//Loop-behandlar lösenordet
	for($i=0; $i < $db_x; $i++)
	{
		$password = md5($static_salt.sha1($password).$db_salt.md5($db_x));
	}

	$baked_pass = sha1($password); //Färdigt lösenord

	return $baked_pass;
}
}
?>

 

connect.php

<?php
$hostname = 'address'; // Adress till databasen
$username = '****'; //Användarnamn för databasen
$password = '****'; //Lösenord för databasen
$database = '****'; //Namnet på databasen

//Låt denna variabel vara som den är. Används för att införa datum och tid i databasen
$date = date("Y-m-d");


//Följande skapar själva anslutningen till database
try {
$conn = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
}

catch(PDOException $e)
    {
echo $e->getMessage();
    }
?>

Link to comment
Share on other sites

english comments would have be fine for better understanding  :D

 

Unless your code is not vulnerable against sql-injections I didn't find security problems. You are using SHA-1 which is broken, but still  should be more secure than MD5 (also broken) - so just for information purpose. Keep it in your head, you could use mcrypt functions if available on your server.

 

(...but maybe someone else will find a security issue)

 

kind regards!

Link to comment
Share on other sites

english comments would have be fine for better understanding  :D

 

Unless your code is not vulnerable against sql-injections I didn't find security problems. You are using SHA-1 which is broken, but still  should be more secure than MD5 (also broken) - so just for information purpose. Keep it in your head, you could use mcrypt functions if available on your server.

 

(...but maybe someone else will find a security issue)

 

kind regards!

 

PDO takes care of the SQL-injections.

 

By broken I guess you meen one-way..in other words hash. In my case... the only way to re-create a password that's stored in the database is by bruteforce...or if you want to build a rainbow-table for each pass and take the random salt in consideration.

Link to comment
Share on other sites

no, by broken I don't mean one way. by broken I mean that it is not secure for 100% anymore. it IS possible (possible but still hard and complex) to calculate/figure out passwords which have the same hash.

 

(I'm not saying that your application would need more security, but still it is not perfect - *paranoid* ;) )

Link to comment
Share on other sites

no, by broken I don't mean one way. by broken I mean that it is not secure for 100% anymore. it IS possible (possible but still hard and complex) to calculate/figure out passwords which have the same hash.

 

(I'm not saying that your application would need more security, but still it is not perfect - *paranoid* ;) )

 

The way I figure it... if they (by they I meen hackes) has gained access to the DB....they probably have rooted the server too. I consider my security the last defence and a way to give me time to make the DB they have useless.... useless on my site that is.

 

And by the way.... nothing is 100% secure, it never has been and never will be. Your system may be perfect, but still... the greatest threat is sabotage by employee.  ;D

 

So... always tell the staff how mutch you love them before you go to bed  ;D

Link to comment
Share on other sites

when I talk about 100% secure I'm talking about an algorithm that isn't hackable - by now. It is possible that maybe someone finds a way to hack it, but at the time it is not possible. And when I talk about "not 100% secure" i mean that it was hacked already.

 

(there could be many ways to get data from your database...)

 

But I'm just informing you -it's up to you what you do with my posts.)

 

kind regards.

Link to comment
Share on other sites

when I talk about 100% secure I'm talking about an algorithm that isn't hackable - by now. It is possible that maybe someone finds a way to hack it, but at the time it is not possible. And when I talk about "not 100% secure" i mean that it was hacked already.

 

(there could be many ways to get data from your database...)

 

But I'm just informing you -it's up to you what you do with my posts.)

 

kind regards.

 

I appreciate your comments...especially since you're the only one who has shown interrest  ;D

The thing is.. I like being critizized and receiving comments..good or bad. It makes me think and in the end.. it makes me a better programmer. I dont always agree, but I always respect good comments.

Link to comment
Share on other sites

  • 2 months later...

class_login.php

 

Warning: Invalid path to PHP binary in config file: /opt/lampp/bin/php

Syntax error

line: 4

 

accounthandler.php

 

Warning: Invalid path to PHP binary in config file: /opt/lampp/bin/php

Syntax error

line: 11

connect.php

Warning: Invalid path to PHP binary in config file: /opt/lampp/bin/php

Syntax error

line: 12

 

Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.