Pereiti prie turinio

PHP slaptažodžių kodavimas


Rekomenduojami pranešimai

Sveiki,

 

planuoju perdaryti slaptažodžių kodavimą naudojant bcrypt (https://github.com/ircmaxell/password_compat), tačiau be šios bibliotekos, nes serveryje yra PHP5.5.

 

Klausimas tas, kaip teisingai duombazėje saugoti slaptažodžius ir hash'ą, pagal kuri būtų tikrinamas slaptažodis?

 

Kiek suprantu, reikėtų naudoti taip:

duombazėje sukuriama lentelė UserLogins. Joje būtų username, password, salt laukai.

username padarome demo, sugeneruojam salt'ą demo ($2y$10$6HF00jhT/ssmMC452AoRtOLYm4EnjE/B0cQW4Fg.sIZYqm8y4rHla) ir tikriname taip:

$password = "demo";
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));
$salt = "$2y$10$6HF00jhT/ssmMC452AoRtOLYm4EnjE/B0cQW4Fg.sIZYqm8y4rHla";
echo $hash."<BR>";
if (password_verify($password, $salt)) {
   echo "ok";
} else {
   echo "failed";
}

 

O kaip į duomenų bazę įrašyti slaptažodį? ar tas salt ir bus slaptažodis, password_hash f-jai $password paduoti per $_POST?

 

Nelabai suprantu dar kaip tai veikia, tad būtų gerai, jeigu galėtumėte konkrečiai paaiškinti kaip tai padaryti su mysql duomenų baze. AČIŪ!

 

Edit:

Prie tos bibliotekos aprašymo yra password rehash ir sakoma, kad kartas nuo karto, reikėtų atnaujinti hashą duombazėje naudojant tokį kodą:

if (password_verify($password, $hash)) {
   if (password_needs_rehash($hash, $algorithm, $options)) {
       $hash = password_hash($password, $algorithm, $options);
       /* Store new hash in db */
   }
}

Tai dar apie šį dalyką norėčiau komentarų...

Redagavo Donatis07
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Viską sumalei sumalei nelabai suprantu ko tiksliai nori.

Jeigu nori išsaugoti į mysql tai paimk $hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));

$result = $db->exec("INSERT INTO users (NickName, Password, Email) VALUES ('".$_POST['Username']."','".$hash."','".$_POST['Email']."')");
$insertId = $db->lastInsertId();

 

Kažkas tokio, čia iš mano kodo. O tikrini tai gerai.

Redagavo arman
Nuoroda į pranešimą
Dalintis kituose puslapiuose

1. Užkoduoti slaptažodį su savo "druska" ir slaptažodžiu.

2. Dedi gautą info į duombazę, vietoj slaptažodžio įrašydamas gautą kodą iš 1. punkto.

 

Prisijungimo validacija:

1. Užkoduoji gautą slaptažodį iš formos su ta pačią "druska".

2. Tikrini, ar email & slaptažodis užkoduotas gautas iš 1. punkto sutampa (t.y. yra tokia eilutė DB).

 

Pseudo kodas įterpimo:

encodedPassword = SHA1("salt" + userPassword)
registerUser(email, encodedPassword)

 

Pseudo kodas patikrinimo:

encodedPassword = SHA1("salt" + userPasswordFromForm)
if (checkLogin(email, encodedPassword) {
 //login success
}
else {
 //wrong credentials
}

 

"Druska" bet kuriuo atveju registracijos ir prisijungimo turi būti naudojama ta pati, kitaip gausi kitokias užkoduotas reikšmes. Saugoti "druską" kaip lentelės lauką - bloga praktika. Tas pats kas iš vis jos nenaudoti.

Nuoroda į pranešimą
Dalintis kituose puslapiuose

na ką gi, prisijungimą padariau tokį:

<?php
class User {

private 	$pdo;
private 	$logged_in 			= false;
private 	$username 			= "";
private 	$password 			= "";

public 		$errors 			= array();

const 		ERROR 				= "Įvyko duomenų bazės klaida. Bandykite prisijungti vėliau.";
const 		SUSPENDED 			= "Prisijungimo vardas suspenduotas.";
const 		ENTER_LOGINS 		= "Įveskite prisijungimo vardą ir slaptažodį.";
const 		WHRONG_LOGINS		= "Neteisingi prisijungimo duomenys.";
const 		INACTIVE_USERNAME 	= "Prisijungimo vardas neaktyvus.";
const 		LOGGED_IN 			= "Prisijungta prie sistemos.";
const 		LOGGED_OUT 			= "Atsijungta nuo sistemos.";

public function __construct($pdo) {
	session_start();
	$this->pdo = $pdo;
	if ($this->logout()):        

	elseif ($this->loginUserSession()):
		$this->logged_in = true;
	elseif ($this->loginUser()):
		$this->logged_in = true;
	endif;
}

private function loginUserSession() {
	if (!empty($_SESSION["user_name"]) && ($_SESSION["logged_in"] == 1)):
		return true;
	else:
		return false;
	endif;
   }

private function loginUser() { 
	if (isset($_POST["login"]) && !empty($_POST["username"]) && !empty($_POST["password"])):
		$this->username = $_POST["username"];
		$this->password = $_POST["password"];
		try {
			$query = $this->pdo->prepare("SELECT * FROM users WHERE user_username=:username");
			$query->bindValue(":username", $this->username, PDO::PARAM_STR);
			$query->execute();
			if ($query->rowCount() > 0):
				$result = $query->fetch(PDO::FETCH_ASSOC);
				if (($result["user_failed_logins"] >= 3) && ($result["user_last_failed_login"] > (time()-60))):
					$this->errors[] = SUSPENDED;
					logLoginError("Login page: ".SUSPENDED);
					return false;
				else:
					if ($result["user_status"] == 1):
						if (password_verify($this->password, $result["user_hash"])):
							$_SESSION["logged_in"] 		= 1;
							$_SESSION['user_id'] 		= $result["user_id"];
							$_SESSION['user_name'] 		= $result["user_username"];
							$_SESSION["user_rights"] 	= $result["user_rights"];
							$_SESSION["user_firstname"]	= $result["user_name"];
							$_SESSION["user_fullname"] 	= $result["user_name"]." ".$result["user_lastname"];
							session_write_close();
							session_regenerate_id(true);
							$logLogin = $this->pdo->prepare("INSERT INTO users (username, ip) VALUES (:username, :ip)");
							$logLogin->execute(array(":username" => $result["user_username"], ":ip" => getRealIP()));
							$lastLogin = $this->pdo->prepare("UPDATE users SET user_login=now(), user_ip=:ip WHERE user_username=:user");
							$lastLogin->execute(array(":ip" => getRealIP(), ":user" => $result["user_username"]));
							if ($result["user_last_failed_login"] > 0):
								$sth = $this->pdo->prepare("UPDATE users SET user_failed_logins=0, user_last_failed_login=NULL WHERE user_id=:user_id AND user_failed_logins!=0");
								$sth->execute(array(":user_id" => $result["user_id"]));
							endif;
							actionsLogging("", self::LOGGED_IN);
							return true;
						else:  // password verify
							$sth = $this->pdo->prepare("UPDATE users SET user_failed_logins=user_failed_logins+1, user_last_failed_login=:user_last_failed_login WHERE user_id=:user_id");
							$sth->execute(array(":user_id" => $result["user_id"], ":user_last_failed_login" => time()));
							$this->errors[] = self::WHRONG_LOGINS;
							logLoginError("Login page: ".self::WHRONG_LOGINS);
							return false;
						endif; // password verify
					else: // check user status
						$this->errors[] = self::INACTIVE_USERNAME;
						logLoginError("Login page: ".self::INACTIVE_USERNAME);
						return false;
					endif; // check user status
				endif; // failed logins
			else: // check user exists
				$this->errors[] = self::WHRONG_LOGINS;
				logLoginError("Login page: ".self::WHRONG_LOGINS);
				return false;
			endif;  // check user exists
		} catch(PDOException $ex) {
			$this->errors[] = self::ERROR;
		    errorLogging($ex->getMessage());
		    return false;
		}
	elseif (isset($_POST["login"]) && (empty($_POST["username"]) || empty($_POST["password"]))):
		$this->errors[] = self::ENTER_LOGINS;
		logLoginError("Login page: ".self::ENTER_LOGINS);
		return false;
	endif;
}

public function logout() {
	if (isset($_GET["logout"]) && ($_GET["logout"] == "")):
		actionsLogging("", self::LOGGED_OUT);
		setcookie("hide_footer", "", time() - 7200, substr(ROOT, 0, -1));
		setcookie("menu_opened", "", time() - 7200, substr(ROOT, 0, -1));
		$_SESSION = array();
		session_destroy();
		//return true;
		header("Location: ".ROOT);
		die();
	endif;
}

public function isLoggedIn() {
	return $this->logged_in;
}
}

 

Viskas veikia, tik įdomu, ar gerai viską atlieku...

Redagavo Donatis07
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Viską sumalei sumalei nelabai suprantu ko tiksliai nori.

Jeigu nori išsaugoti į mysql tai paimk $hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));

$result = $db->exec("INSERT INTO users (NickName, Password, Email) VALUES ('".$_POST['Username']."','".$hash."','".$_POST['Email']."')");
$insertId = $db->lastInsertId();

 

Kažkas tokio, čia iš mano kodo. O tikrini tai gerai.

 

Pataisyk SQL injectioną savo kode :)

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Su apsauga nelabai nusimau, bet tinka tokios eilutės?

$_GET = array_map('mysql_real_escape_string', $_GET); 
$_POST = array_map('mysql_real_escape_string', $_POST);

 

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));
$result = $db->prepare("INSERT INTO users (NickName, Password, Email) VALUES (:nick,:password,:email)");
$result->execute(array(":nick" => $_POST['Username'], ":password" => $hash, ":email" => $_POST['Email']));
$insertId = $db->lastInsertId();

Paskaityk čia

Redagavo Donatis07
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Saugoti "druską" kaip lentelės lauką - bloga praktika. Tas pats kas iš vis jos nenaudoti.

Ką? O tai kur saugosi druską, unikalią kiekvienam vartotojui, vienaragio urve? :) Vis tiek pakelia slaptažodžio crackinimo trumę n kartų, kur n – vartotojų skaičius. Nesvarbu, kad lengvai prieinama.

 

Ne-unikalus salt yra beveik tas pats, kas jokio salt, nes beveik neprailgina crackinimo laiko (tik tiek, kol pamodifikuosi žodyną), apsaugo tik nuo rainbow tables.

 

Kiek žinau, nėra stebuklingų vietų, kur tavo aplikacija galėtų pasiekti salt, o įsilaužėlis – ne.

 

SHA1 apskritai nėra slaptažodžiams skirta hešavimo funkcija. Geriau naudoti autoriaus minimą bcrypt ar kitą daug laiko trunkantį algoritmą, apie ką ir buvo klausta.

 

password_hash() saugią druską sugeneruoja pats.

 

--

 

Donatai, cost turėtų būti konstanta ar parametras kur nors klasėje – nori galėti ją nesunkiai pakeisti. Tuo labiau, kad 10 nėra jau toks didelis sunkumas.

 

Šiaip dar baisokai atrodo primaišytos PHP normali sintaksė ir alternatyvi... Ne vien dėl to, kad alternatyvi dažniausiai nenaudojama (išskyrus kai kurias templeitų „sistemas“, kur grynas PHP), bet dar ir dėl to, kad jos abi vienoj vietoj... Gal geriau pasilik prie įprastos?

 

Dar su bcrypt būtų gerai turėti rate limitingą. Kai nėra jo, su tokia intensyvia funkcija piktavalis gali išsunkti serverio CPU resursus :) Ai, berods tą turi su SUSPENDED.

 

Rehash yra reikalingas tik tada, kai pasikeičia algoritmas (bcrypt) ar jo parametrai (pvz., cost). Kitokiu atveju tavo rehash tik pakeis saltą, ir tiek.

Redagavo Silke
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Prisijunkite prie diskusijos

Jūs galite rašyti dabar, o registruotis vėliau. Jeigu turite paskyrą, prisijunkite dabar, kad rašytumėte iš savo paskyros.

Svečias
Parašykite atsakymą...

×   Įdėta kaip raiškusis tekstas.   Atkurti formatavimą

  Only 75 emoji are allowed.

×   Nuorodos turinys įdėtas automatiškai.   Rodyti kaip įprastą nuorodą

×   Jūsų anksčiau įrašytas turinys buvo atkurtas.   Išvalyti redaktorių

×   You cannot paste images directly. Upload or insert images from URL.

Įkraunama...
  • Dabar naršo   0 narių

    Nei vienas registruotas narys šiuo metu nežiūri šio puslapio.

  • Prisijunk prie bendruomenės dabar!

    Uždarbis.lt nariai domisi verslo, IT ir asmeninio tobulėjimo temomis, kartu sprendžia problemas, dalinasi žiniomis ir idėjomis, sutinka būsimus verslo partnerius ir dalyvauja gyvuose susitikimuose.

    Užsiregistruok dabar ir galėsi:

    ✔️ Dalyvauti diskusijose;

    ✔️ Kurti naujas temas;

    ✔️ Rašyti atsakymus;

    ✔️ Vertinti kitų žmonių pranešimus;

    ✔️ Susisiekti su bet kuriuo nariu asmeniškai;

    ✔️ Naudotis tamsia dizaino versija;

    ir dar daugiau.

    Registracija trunka ~30 sek. ir yra visiškai nemokama.

  • Naujausios temos

  • Karštos temos

×
×
  • Pasirinkite naujai kuriamo turinio tipą...