C, PHP, VB, .NET

Дневникът на Филип Петров


* Упражнение 2, 2015

Публикувано на 18 март 2015 в раздел ОСУП.

В това упражнение показваме login форма. Паролите са хеширани със salt (уникален ключ за всеки потребител в базата) и pepper (един общ salt в кода).

База от данни – мястото, където ще записваме потребителските имена и пароли. Създаваме си уникален потребител специално за login формата.

CREATE DATABASE upr2;
USE upr2

CREATE TABLE users(
 id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
 user VARCHAR(64) NOT NULL UNIQUE,
 pass CHAR(96) NOT NULL,
 salt CHAR(96) NOT NULL
);

GRANT SELECT ON upr2.users
TO loginform@localhost
IDENTIFIED BY 'fghjudighfduishgiufdsw';

passgen.php – използвайте този скрипт, за да си генерирате insert заявки за вмъкване на потребители в базата данни

<?php
DEFINE("PEPPER", 'jfrikl^#@&*wsa^$#&*gjr__--eiu--AAa');
DEFINE("KEYSTRECHITERATIONS", 100000);
	
$user = "ivan";
$pass = "123456";

// Този salt определено е прекалено дълъг
// може да използвате значително по-къс
// без това да навреди на сигурността
$salt = base64_encode(openssl_random_pseudo_bytes(72));
for($i=0; $i<KEYSTRECHITERATIONS; $i++){
	$pass = hash("sha384", $salt.$pass.PEPPER);
}
echo "INSERT INTO users(user, pass, salt)
VALUES('".$user."', 
'".$pass."', 
'".$salt."')";
?>

index.php – главната страница на сайта, в която показваме формата за вход.

<?php
	session_start();
?>
<html><head><title>Login page</title></head>
<body>
<form action="login.php" method="POST">
USER: <input type="text" name="user" /><br />
PASS: <input type="password" name="pass" /><br />
<input type="submit" name="loginbutton" value="Login!" /><br />
</form><br />
<?php
	if(isset($_SESSION['error'])){
		echo $_SESSION['error'];
		session_unset();
		session_destroy();
	}
?>
</body></html>

login.php – скрипта, който извършва автентикацията.

<?php
DEFINE("DBHOST", "localhost");
DEFINE("DBUSER", "loginform");
DEFINE("DBPASS", "fghjudighfduishgiufdsw");
DEFINE("DBNAME", "upr2");
DEFINE("PEPPER", 'jfrikl^#@&*wsa^$#&*gjr__--eiu--AAa');
DEFINE("HASHALGO", "sha384");
DEFINE("KEYSTRECHITERATIONS", 100000);

// Проверява дали има попълнена форма
function POSTVarsExists(){
	return (isset($_POST['user']) 
			&& isset($_POST['pass']) 
			&& isset($_POST['loginbutton']));
}
	
// Проверява за валиден формат на името и паролата
// Приели сме потребителски имена от 4 до 64 букви/цифри
// и пароли от 6 до 64 символа (каквито и да е).
function userAndPassAreValidFormat($user, $pass){
	return (is_string($user)
                && is_string($pass)
                && strlen($pass)>=6 
		&& strlen($pass)<=64
		&& preg_match("/^[a-zA-Z0-9_-]{4,64}$/",$user));
}

// С тази функция се пренасочваме обратно към index.php
function backToIndex($error){
	switch($error){
		case 0: break;
		case 1:	session_start();
			session_unset();
			$_SESSION['error'] 
		          = "Invalid username OR password";
			break;
		case 2:	session_start();
			session_unset();
			$_SESSION['error'] 
		          = "Technical issues. Come back later";
			break;
	}
	header("Location: index.php");
}

// Ако не сме попълнили форма, се връщаме към index
if(!POSTVarsExists()){
	backToIndex(0);;
	exit;		
}

// Ако сме попълнили име или парола, които не отговарят
// на стандартния формат, се връщаме към index с грешка
if(!userAndPassAreValidFormat(
	$_POST['user'], $_POST['pass']
  )){
	backToIndex(1);
	exit;		
}

$user = $_POST['user'];
$pass = $_POST['pass'];

// Свързване с базата от данни
$link = @mysqli_connect(DBHOST,DBUSER,DBPASS,DBNAME);
if(!$link){
	backToIndex(2);
	exit;
}

// Това може да се пропусне	
$user = @mysqli_real_escape_string($link, $user);

// Изпълняваме SQL заявка
$sql = "SELECT id, pass, salt 
        FROM users 
	WHERE '".$user."' = user
	LIMIT 1";
$result = @mysqli_query($link, $sql);
if(!$result){
	backToIndex(2);
	@mysqli_close($link);
	exit;		
}

// Взимаме ред от резултата от заявката
$row = @mysqli_fetch_assoc($result);
// Ако няма върнат ред, това е невалидно име/парола
if(!isset($row['id'])){
	backToIndex(1);
	@mysqli_close($link);
	exit;		
}

// Хешираме подадената от потребителя парола
for($i=0; $i<KEYSTRECHITERATIONS; $i++){
	$pass = hash(HASHALGO, $row['salt'].$pass.PEPPER);
}

// Ако не съвпада с паролата от БД, връщаме към index
if($pass !== $row['pass']){
	backToIndex(1);
	@mysqli_close($link);
	exit;	
}

// Ако всичко е наред, продължаваме към securearea	
session_start();
session_unset();
session_regenerate_id(true);
$_SESSION['userid'] = $row['id'];
header("Location: securearea.php");
exit;
?>

securearea.php – мястото, където искаме да влезнем.

<?php
session_start();
if(!isset($_SESSION['userid'])){
	header("Location: index.php");
	exit;
}
?>
<html><head><title>Secure area</title></head>
<body>
<?= "Hello ".$_SESSION['userid'] ?>
</body></html>

 



Добави коментар

Адресът на електронната поща няма да се публикува


*