Using what PHP provides, you should work with PHP's Password Hashing functions. / p>
password_hash
You must create and store the hash of the password in some repository (database, etc ...). To perform the hash, you must use the password_hash
$passwordHash = password_hash($_POST['password'] , PASSWORD_DEFAULT);
In the first parameter is the password you want to store and the second is the algorithm that will be used for the password. According to the manual (which you can also read in this answer ), it is recommended to use PASSWORD_DEFAULT
.
The hash that is generated will always be different, and as an example, for the password teste123
, generated the hash below:
$ 2 and $ 10 $ kPsVvPp8Z1K73vEW / fHcHewbkkQNTN0JOdLPEwoydf8y4pO32Ixqu
You can check this link for hash generation: link
password_verify
When validating the password, you must use the password_verify
function. As the example below:
password_verify ($_POST['senha'], $hash);
Being the variable $hash
, the hash that was returned by the password_hash
function and saved in storage.
Example:
$senha = "teste123";
$hash = '$2y$10$kPsVvPp8Z1K73vEW/fHcHewbkkQNTN0JOdLPEwoydf8y4pO32Ixqu';
echo password_verify ($senha , $hash) ? 'Senha válida' : "Senha inválida";
Output:
Valid password
Working Code: link
Authentication and Security
To further improve authentication security, there are a few steps to follow. The first is not to differentiate between invalid user or password. Well, attacking, knowing that a user is valid, will only focus on it to try to locate the password.
Secondly, there is something called Timming Attack. Which, in short, consists of checking how long the algorithm takes to respond that the password is invalid and comparing these times with different passwords, to find correct characters within a password. You can read about this this link
The password_verify
function already has defense against Timming Attack, but should be used correctly.
With this in mind, we can get to the following script:
//criado utilizando o seguinte código: password_hash("dummy_password" , PASSWORD_DEFAULT);
define("DUMMY_PASSWORD" , '$2y$10$bev5nl962WWcwa1G2gyXyunkKY77Xf7OTr.1I3zcl7Qd4zFYCqXjC');
$usuario = $_POST['usuario'];
$pdo = new \PDO(/** dados de conexão**/);
$statement = $pdo->prepare('SELECT * FROM user WHERE login = ?');
$statement->execute([$usuario]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
if(!$row)
{
// Usuário não existe
// A validação é feita em uma senha qualquer
//para que o tempo de resposta entre uma consulta que o usuário não exista
//e uma consulta que o usuário exista e a senha esteja errada seja o mesmo.
password_verify("" , DUMMY_PASSWORD);
throw new \RuntimeException('Usuário/Senha não confere');//usuário não existe, mas a mensagem é genérica para evitar força bruta
}
if(!password_verify($_POST['senha'] , $row['password']))
{
//usuário existe, mas a mensagem é genérica para evitar força bruta
throw new \RuntimeException('Usuário/Senha não confere');
}
echo 'usuário logado';
The PDO
library was used to simplify the connection to the database and to protect against SQL Injection .
Remembering, this is just an example algorithm, with a secure and effective way of login / authentication. The details of session creation, redirection, should be implemented as needed.