Using what PHP provides, you should work with the functions Password Hashing of PHP.
password_hash
You must create and store the password hash in some repository (database, etc...). To perform the hash, you must use the function 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:
$2y$10$kPsVvPp8Z1K73vEW/fHcHewbkkQNTN0JOdLPEwoydf8y4pO32Ixqu
You can check this link for hash generation: https://3v4l.org/3eDee
password_verify
When validating the password, you must use the function password_verify
. As the example below:
password_verify ($_POST['senha'], $hash);
Being the variable $hash
, the hash that was returned by the function password_hash
and saved in the Torage.
Example:
$senha = "teste123";
$hash = '$2y$10$kPsVvPp8Z1K73vEW/fHcHewbkkQNTN0JOdLPEwoydf8y4pO32Ixqu';
echo password_verify ($senha , $hash) ? 'Senha válida' : "Senha inválida";
Exit:
Valid password
Code in operation: https://3v4l.org/ksn1J
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. Because the attacker, knowing that a user is valid, will focus only on him to try to locate the password.
Second, there’s something called Timming Attack. That, briefly, consists of checking how long the algorithm takes to respond that the password is invalid and comparing these times with different passwords, to locate correct characters within a password. You can read about it at this link
The function password_verify
already has defense against Timming Attack, but should be used correctly.
With that in mind, we can arrive at 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 library was used PDO
to simplify connection to the database and protect against SQL Injection.
Remember, this is just an example algorithm, with a secure and effective form of login/authentication. Session creation details, redirect, should be implemented as needed.
First, what API is using to manage the bank?
MySQLi
orPDO
? Second, read about SQL Injection. Third, if the last line of code should redirect the user, the header name was missingLocation
. Also it doesn’t make much sense you print the message in the body of the reply if it will redirect.– Woss