Created
May 8, 2020 17:52
-
-
Save jakubboucek/3938f12b43e10a372fb822b09d1b561c to your computer and use it in GitHub Desktop.
AutoPassword
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
class AutoPasswords | |
{ | |
/** @var IPasswords[] */ | |
private $passwords; | |
/** @var IPasswords */ | |
private $defaultPasswords; | |
/** | |
* @param IPasswords[] $passwords | |
* @param IPasswords $defaultPasswords | |
*/ | |
public function __construct(array $passwords, IPasswords $defaultPasswords) | |
{ | |
$this->passwords = $passwords; | |
$this->defaultPasswords = $defaultPasswords; | |
} | |
public function matchHash(string $hash, bool $isTransientPassword): IPasswords | |
{ | |
foreach ($this->passwords as $passwords) { | |
$matched = $passwords->matchHash($hash, $isTransientPassword); | |
if ($matched instanceof IPasswords) { | |
return $matched; | |
} | |
} | |
throw new NotMatchPasswordsException('Unable to match right password hast algoritm for hash'); | |
} | |
/** | |
* Hash password with default passwords (most secure hash) | |
* | |
* @param string $password | |
* @return string | |
*/ | |
public function hash(string $password): string | |
{ | |
return $this->defaultPasswords->hash($password); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
use Nette\Security\Passwords; | |
class Bcrypt implements IPasswords | |
{ | |
/** @var Passwords */ | |
private $passwords; | |
public function __construct(Passwords $passwords) | |
{ | |
$this->passwords = $passwords; | |
} | |
public function matchHash(string $hash, bool $isTransientPassword): ?IPasswords | |
{ | |
// Not transient (bcrpyt + sha1) and not old version (sha1) | |
$isMatched = $isTransientPassword === false && strpos($hash, '$2y$') === 0; | |
return $isMatched ? $this : null; | |
} | |
public function hash(string $password): string | |
{ | |
return $this->passwords->hash($password); | |
} | |
public function verify(string $password, string $hash): bool | |
{ | |
return $this->passwords->verify($password, $hash); | |
} | |
public function needsRehash(string $hash): bool | |
{ | |
return $this->passwords->needsRehash($hash); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Toto je example pro použití tříd. Vyžaduje composer balíček "nette/security". | |
* | |
* Je to systém použitelný pro přehashování hesel z SHA1 na BCRYPT. Vzhledem k tomu, že nelze získat původní | |
* podobu hesel, jsou hesla v SHA1 zahashována do tvaru `password_hash(sha1($heslo))` - tento stav | |
* se nazývá Transient (přechodný). | |
* | |
* Níže uvedený kód umí detekovat typ použitého hashe a vrátí knihovnu, která s danám hashem umí pracovat. | |
* | |
* Jsou 3 typy hashů: | |
* - Bcrypt => to je požadovaný hash. Kdykoliv je potřeba zahashovat heslo, MUSÍ se zvolit tento algoritmus | |
* - Sha1 => původníhash - nyní je použitelný pouze pro ověření hesla. | |
* - Transient => Přechodný algoritmus hashe získaný pomocí `password_hash(sha1($heslo))` | |
* | |
* Protože je | |
*/ | |
$bcrypt = new Bcrypt(new Nette\Security\Passwords()); | |
$sha1 = new Sha1('any-security-salt'); | |
$transient = new Transient($bcrypt,$sha1); | |
$autoPassword = new AutoPasswords([$bcrypt, $transient, $sha1], $bcrypt); | |
// =========== zahashování hesla | |
$hash = $autoPassword->hash('tajne-heslo'); | |
// =========== ověření hesla | |
// hash hesla z DB | |
$hash = '$2y$10$Mu3jFu5VtyzKKOKRju5QduGKEYXi11mvcSYx.L2f98tuuppk5uoHe'; | |
$isTransient = true/false; // určuje, zda je heslo bcrypt(heslo) a nebo bcrypt(sha1) | |
$verifier = $autoPassword->matchHash($hash, $isTransient); | |
$isValidPassword = $verifier->verify('tajne-heslo', $hash); | |
// Chybné heslo - vykopnem další zpracování | |
if($isValidPassword !== true) { | |
throw new Exception("špatné heslo"); | |
} | |
// zjistíme, zda bychom měli heslo přehashovat | |
if($verifier->needsRehash($hash)) { | |
// využijeme příležitosti, že nám uživatel zadal heslo a rovnou ho přehashujeme do správného tvaru | |
$hash = $autoPassword->hash('tajne-heslo'); | |
$isTransient = false; | |
// uložíme do DB nový hash | |
save($hash, $isTransient); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
interface IPasswords | |
{ | |
public function matchHash(string $hash, bool $isTransientPassword): ?IPasswords; | |
public function hash(string $password): string; | |
public function verify(string $password, string $hash): bool; | |
public function needsRehash(string $hash): bool; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
use RuntimeException; | |
class NotMatchPasswordsException extends RuntimeException | |
{ | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
class Sha1 implements IPasswords | |
{ | |
/** @var string */ | |
private $securitySalt; | |
public function __construct(string $securitySalt) | |
{ | |
$this->securitySalt = $securitySalt; | |
} | |
public function matchHash(string $hash, bool $isTransientPassword): ?IPasswords | |
{ | |
// Is sha1, isTransientPassword doesn't matter | |
$isMatched = (bool)preg_match('/^[a-f0-9]{40}$/D', $hash); | |
return $isMatched ? $this : null; | |
} | |
public function hash(string $password): string | |
{ | |
return sha1($password . $this->securitySalt); | |
} | |
public function verify(string $password, string $hash): bool | |
{ | |
return hash_equals($hash, $this->hash($password)); | |
} | |
public function needsRehash(string $hash): bool | |
{ | |
// Deprecated alg | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
class Transient implements IPasswords | |
{ | |
/*** @var Sha1 */ | |
private $sha1; | |
/** @var Bcrypt */ | |
private $passwords; | |
public function __construct(Bcrypt $passwords, Sha1 $sha1) | |
{ | |
$this->sha1 = $sha1; | |
$this->passwords = $passwords; | |
} | |
public function matchHash(string $hash, bool $isTransientPassword): ?IPasswords | |
{ | |
// Is transient (bcrpyt + sha1) and not old version (sha1) | |
$isMatched = $isTransientPassword === true && strpos($hash, '$2y$') === 0; | |
return $isMatched ? $this : null; | |
} | |
public function hash(string $password): string | |
{ | |
return $this->passwords->hash($this->sha1->hash($password)); | |
} | |
public function verify(string $password, string $hash): bool | |
{ | |
return $this->passwords->verify($this->sha1->hash($password), $hash); | |
} | |
public function needsRehash(string $hash): bool | |
{ | |
// Deprecated alg | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment