Porównywanie zaszyfrowanego hasła funkcją crypt()

0

Witam, mam problem z porównywaniem hasła zaszyfrowanego za pomocą funkcji crypt(). Wszystko to robię za pomocą obiektowego PHP.

Kod modelu:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

require_once '../database/sql_database.class.php';
require_once 'login.class.php';
if(isset($_POST['submitLogin'])){
	$dbObject = new SqlDatabase();
	$loginUser = new LoginUser($dbObject->getInstance());
	
	$loginUser->getNickname($_POST['nickname']);
	$loginUser->getPassword($_POST['password']);
	
	if ($loginUser->doValidate()) {
		if ($loginUser->isUser()) {
			if(crypt($loginUser->getPassword($_POST['password'], $_POST['password']) == $_POST['password'])){
                                //tu sobie dodam sesję i całą resztę logowania
				echo 'Zostałeś pomyślnie zalogowany';
			}
			} else {
			echo sprintf('<div class="error">Wystąpił błąd podczas logowania: %s</div>', $loginUser->getErrorMessage());
		}
		} else {
		echo sprintf('<div class="error">Błąd: %s</div>', $loginUser->getErrorMessage());
	}
}
?>

Chodzi konkretniej o:

if(crypt($loginUser->getPassword($_POST['password'], $_POST['password']) == $_POST['password'])){
	//tu sobie dodam sesję i całą resztę logowania
	echo 'Zostałeś pomyślnie zalogowany';
}

Wiem, że coś tu pochrzaniłem. W strukturalnym kodzie miałem taki analogiczny kod:

if(crypt($password, $data['password']) == $data['password'])

W moim przypadku ów $password filtrowane jest w metodzie doFilter. Jest to "odniesienie" to pola o takiej nazwie. Tak wygląda ta metoda:

public function doFilter(){
	$this->nickname = trim($this->nickname);
	$this->password = trim($this->password);
	return $this;
}

Nie wiem jak odwołać się do pola "password" przy użyciu funkcji crypt().
Ma ktoś jakiś pomysł?

0

Hasło nie powinno być szyfrowane!
Do bazy zapisuj hashe (np. md5/sha256) i to je porównuj.

Poza tym co to jest: $loginUser->isUser(). To w jakiś sposób użytkownik może nie być użytkownikiem?

No i drobna dygresja odnośnie sql_database.class.php - skoro klasa nazywa się sqldatabase, to nazwa w pliku również powinna być bez podkreślnika.

0
Patryk27 napisał(a):

Hasło nie powinno być szyfrowane!

funkcja crypt nie służy do szyfrowania tylko hashowania

Do bazy zapisuj hashe (np. md5/sha256) i to je porównuj.

Takie bzdury nie powinny być już powielane w Internecie
md5 było bezpieczne 10 lat temu, sha256 może 3 lata temu - na dzień dzisiejszy jeżeli chodzi o realne bezpieczeństwo, nie powinno się używać żadnego z tych algorytmów
najlepiej użyć blowfish, ewentualnie sha512

0

funkcja crypt nie służy do szyfrowania tylko hashowania

Racja, moje przeoczenie - sugerowałem się tytułem wątku.

Takie bzdury nie powinny być już powielane w Internecie (...)

Przecież to dział newbie, autor nie pisze niczego dla NSA.


Anyway, wrzuć kod klasy `LoginUser`.
1
Patryk27 napisał(a):

Przecież to dział newbie, autor nie pisze niczego dla NSA.

w takim razie równie dobrze mógłby sobie porównywać plaintext

0

Źle się wyraziłem. Chodziło mi o hashowanie i porównywanie hash`u przy logowaniu.
Tak wygląda klasa login.class.php:

<?php
	class LoginUser{
		private $dbHandler;

		public function __construct($db){
			$this->dbHandler = $db;
		}

		private $nickname, $password;

		public function doFilter(){
			$this->nickname = trim($this->nickname);
			$this->password = trim($this->password);
			return $this;
		}

		public function doValidate(){
			$this->errorMessage = '';
			$this->doFilter();

			if(empty($this->nickname)){
				$this->errorMessage = 'Musisz podać swój nick!';
				return false;
			}
			if(empty($this->password)){
				$this->errorMessage = 'Musisz podać swoje hasło!';
				return false;
			}
			return true;
		}
		public function getErrorMessage(){
			return $this->errorMessage;
		}
		public function getNickname($nickname){
			$this->nickname = $nickname;
		}
		public function getPassword($password){
			$this->password = $password;
		}

		public function isUser(){
			$isUser = $this->dbHandler->prepare("SELECT * FROM `users` WHERE `nickname` = BINARY :nickname AND `password` = BINARY :password");
			$isUser->bindValue(':nickname', $this->nickname, PDO::PARAM_STR);
			$isUser->bindValue(':password', $this->password, PDO::PARAM_STR);
			if($isUser->execute() == false){
				print_r($isUser->errorInfo());
				return false;
				}else{
				return $isUser->fetchAll(PDO::FETCH_ASSOC);
			}
			return true;
		}
	}
0

Dlaczego metody get cokolwiek przypisują czemukolwiek?
Zamiast isUser lepiej już userExists wpisać.

0

Przy rejestracji hashujesz hasło usera i zapisujesz do bazy. Później, podczas logowania pobierasz ten hash z bazy i tworzysz nowy z hasła podanego przy logowaniu. Następnym krokiem jest porównanie obydwu hashy. Jeśli są takie same to znaczy, że user podał prawidłowe hasło. Do poczytania:
http://php.net/manual/en/faq.passwords.php

0
Patryk27 napisał(a):

Hasło nie powinno być szyfrowane!
Do bazy zapisuj hashe (np. md5/sha256) i to je porównuj.

Poza tym co to jest: $loginUser->isUser(). To w jakiś sposób użytkownik może nie być użytkownikiem?

No i drobna dygresja odnośnie sql_database.class.php - skoro klasa nazywa się sqldatabase, to nazwa w pliku również powinna być bez podkreślnika.

A jak zatem powinno to wyglądać, gdy nie jest użytkownikiem?

Patryk27 napisał(a):

Dlaczego metody get cokolwiek przypisują czemukolwiek?
Zamiast isUser lepiej już userExists wpisać.

Rozumiem, że mają coś zwracać. Tylko co takiego powinny zwracać?

0

A jak zatem powinno to wyglądać, gdy nie jest użytkownikiem?

Ale co to znaczy, że użytkownik (ponieważ coś reprezentowanego przez klasę LoginUser siłą rzeczy nim musi być) nie jest użytkownikiem?
To tak, jak gdybyś stworzył klasę Rectangle i metodę CzyJestemProstokątem().
Jak mówiłem, lepsza nazwa to doesUserExist, a jeszcze lepiej to po prostu zrobić metodę doLogin, która zwraca enum, gdzie masz LOGIN_OK, LOGIN_INVALID_CREDENTIALS, LOGIN_USER_DOES_NOT_EXIST i po problemie.

Rozumiem, że mają coś zwracać. Tylko co takiego powinny zwracać?

setXyz - ustawia xyz, getXyz - zwraca xyz, zatem:
setPassword($password) - ustawia pole $password w klasie, a getPassword zwraca to pole.

0

W jaki sposób bym miał zwrócić enum? Może się mylę(popraw mnie jeśli tak) ale wydaje mi się, że w php nie ma jako takiej talicy ENUM. Są tylko jakieś "zewnętrzne" klasy.
Rozumiem, że tak na dobrą sprawę nie muszę używać get tylko set? Mimo tego zwraca mi się błąd pustego pola. Ale nie o to chodzi. Kolejny problem. To klasa:

<?php
	class LoginUser{
		private $dbHandler;

		public function __construct($db){
			$this->dbHandler = $db;
		}

		private $nickname, $password;

		public function doFilter(){
			$this->nickname = trim($this->nickname);
			$this->password = trim($this->password);
			return $this;
		}

		public function doValidate(){
			$this->errorMessage = '';
			$this->doFilter();

			if(empty($this->nickname)){
				$this->errorMessage = 'Musisz podać swój nick!';
				return false;
			}
			if(empty($this->password)){
				$this->errorMessage = 'Musisz podać swoje hasło!';
				return false;
			}
			return true;
		}
		public function getErrorMessage(){
			return $this->errorMessage;
		}
		public function setNickname($nickname){
			$this->nickname = $nickname;
		}
		public function setPassword($password){
			$this->password = $password;
		}

		public function userExists(){
			$userExists = $this->dbHandler->prepare("SELECT 1 FROM `users` WHERE `nickname` = BINARY :nickname AND `password` = BINARY :password");
			$userExists->bindValue(':nickname', $this->nickname, PDO::PARAM_STR);
			$userExists->bindValue(':password', $this->password, PDO::PARAM_STR);
			if($userExists->execute() == false){
				print_r($userExists->errorInfo());
				return false;
				}else{
					$_SESSION['logged'] = true;
					$_SESSION['nickname'] = $this->nickname;
					$_SESSION['password'] = $this->password;
					return $userExists->fetchAll(PDO::FETCH_ASSOC);
			}
			return true;
		}
	}

A to model:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

require_once '../database/sql_database.class.php';
require_once 'login.class.php';
if(isset($_POST['submitLogin'])){
	$dbObject = new SqlDatabase();
	$loginUser = new LoginUser($dbObject->getInstance());
	
	$loginUser->setNickname($_POST['nickname']);
	$loginUser->setPassword($_POST['password']);
	
	if ($loginUser->doValidate()) {
		if ($loginUser->userExists()) {
			
			var_dump($_SESSION['logged']);
			var_dump($_SESSION['nickname']);
			var_dump($_SESSION['password']);
			//if(crypt($loginUser->getPassword($_POST['password'], $_POST['password']) == $_POST['password'])){
				echo 'Zostałeś pomyślnie zalogowany';
				//}
			}else{
			echo 'Błędny login lub hasło!';
		}
		}else{
		echo sprintf('<div class="error">Błąd: %s</div>', $loginUser->getErrorMessage());
	}
}
session_start();
if(isset($_SESSION['logged'])){
	echo 'Logged';
	}else{
	echo 'No';
}
?>

Jeśli wykona się:

if ($loginUser->userExists()) {

To zwraca mi to:
bool(true) string(3) "das" string(2) "da" Zostałeś pomyślnie zalogowanyNo

Potem gdy odświeżę to tej sesji już nie ma. Dlaczego?

0

Może się mylę(popraw mnie jeśli tak) ale wydaje mi się, że w php nie ma jako takiej talicy ENUM. Są tylko jakieś "zewnętrzne" klasy.

Generalnie masz rację, skorzystałem ze skrótu myślowego.


Za dużo odpowiedzialności przerzucasz na jedną metodę. 1.Zmień nazwę z `userExists` na `doLogin`, ponieważ to robi. Niech zwraca `true`/`false`, tak na początek. Ewentualnie może jeszcze ustawiać `errorMessage` np. na `Użytkownik nie istnieje`, `Błędne hasło` czy co tam jeszcze chcesz. 2.Nie twórz sesji w tym, już nowym, `doLogin`, tylko w "modelu". 3.Sesja nie jest zapamiętywana, ponieważ najpierw coś do niej piszesz, a dopiero potem wykonujesz `session_start` - powinno być na odwrót (tj. najpierw tworzysz sesję, a potem coś do niej zapisujesz). 4.Formalnie `modelem` jest klasa `LoginUser`, a tamten plik, który Ty nazywasz modelem, to `kontroler`.
0

Ok, dzięki za rady. Czyli wychodzi na to, że zawsze myślałem, że model to kontroler :) Źle coś musiałem doczytać, teraz będę wiedzieć.

Teraz co do sesji to ustawiłem tak:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

require_once '../database/sql_database.class.php';
require_once 'login.class.php';
if(isset($_POST['submitLogin'])){
	$dbObject = new SqlDatabase();
	$loginUser = new LoginUser($dbObject->getInstance());
	
	$loginUser->setNickname($_POST['nickname']);
	$loginUser->setPassword($_POST['password']);
	
	if ($loginUser->doValidate()) {
		if ($loginUser->doLogin()) {
			session_start();
			$_SESSION['logged'] = true;
			$_SESSION['nickname'] = $_POST['nickname'];
			$_SESSION['password'] = $_POST['password'];
			var_dump($_SESSION['logged']);
			var_dump($_SESSION['nickname']);
			var_dump($_SESSION['password']);
			//if(crypt($loginUser->getPassword($_POST['password'], $_POST['password']) == $_POST['password'])){
				echo 'Zostałeś pomyślnie zalogowany';
				//}
			}else{
			echo 'Błędny login lub hasło!';
		}
		}else{
		echo sprintf('<div class="error">Błąd: %s</div>', $loginUser->getErrorMessage());
	}
}

if(isset($_SESSION['logged'])){
	echo 'Logged';
	}else{
	echo 'No';
}
?>

Tak przynajmniej zrozumiałem. I teraz efekt. W momencie przesyłania się formularza, var_dump`y i isset zwracają mi:

bool(true) string(3) "das" string(2) "da" Zostałeś pomyślnie zalogowanyLogged
czyli sesja jest utworzona i poprawie sprawdzana. Gdy teraz ponownie otworzę tą stronę, klikając w ten sam link do niej prowadzący lub po prostu ją odświeżę to otrzymuję komunikat "No", czyli sesja zniknęła. Dlaczego tak się dzieje?

0

Musisz dać session_start(); na sam początek skryptu, inaczej PHP nie wczyta sesji, która już istnieje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1