HTML & PHP - unread HTML code

2

I have following code on the part of PHP does not present any error, the page appears blank and does not show the HTML code.

<?php
include("config.php");
if($_GET['key'] && $_GET['reset'])
{
  $email=password_hash($_GET['key'],PASSWORD_DEFAULT);
  $pass=password_hash($_GET['reset'],PASSWORD_DEFAULT);
  $sql=mysqli_query($conn,"SELECT email, password FROM registo where email='$email' and password='$pass'");
  if(mysqli_num_rows($sql)==1)
  {
    ?>
<html>
    <form method="post" action="update_newpassword.php">
    <input type="hidden" name="email" value="<?php echo $email;?>">
    <p>Enter New password</p>
    <input type="password" name='password'>
    <input type="submit" name="submit_password">
    </form>
    </html>
    <?php

  }
}
?>
    
asked by anonymous 15.05.2017 / 00:10

1 answer

5

The problem is logical and predictable by the behavior of BCrypt. I'll try to pass on a basics of BCrypt behavior.

But, here's what to do:

<?php

$senha = "a-mesma-senha";

echo password_hash($senha,PASSWORD_DEFAULT);

Will return:

$2y$10$l1Ka5O0C9oYxyY./MvA5YOH1JBTjcY9qTefOLUrZMZ8R4H8kR3UmO

But, the same code will return:

$2y$10$J.eVvzGeh4FQh9uHb8Exz.U9jfn8hJhXs58bvdBYITkLfjLAJp0aK

And without changing anything, it also returns:

$2y$10$VFXgZFjjRLqeQvGIdeAtiuQR8jt1x.6wiz/L4dSBWC5w8fUbWwgDu

See for yourself, click on "Execute Code" several times and the result will always be different

This is self-explanatory. When you do INSERT you enter for example:

$2y$10$l1Ka5O0C9oYxyY./MvA5YOH1JBTjcY9qTefOLUrZMZ8R4H8kR3UmO

But when you do this again you try to search for, in SELECT :

$2y$10$VFXgZFjjRLqeQvGIdeAtiuQR8jt1x.6wiz/L4dSBWC5w8fUbWwgDu

Of course they are different and you will not find them.

This code set with $ in the middle represents:

$<algo>$<dificuldade>$<sal (22 caracteres)><senha (31 caracteres)>

Just the curiosity title and for what you knew how this works note that if you do this:

// Não utilize isto em produção!

// Gera o BCrypt
$hashUm = password_hash('senha', PASSWORD_DEFAULT);

// Obtem o salt da hash gerada (primeiros 22 caracteres após o último $):
$salt = substr(substr($hashUm, strrpos($hashUm, '$')), 1, 22);

// Gera um nova senha COM O MESMO SALT:
$hashDois = password_hash('senha', PASSWORD_DEFAULT, ['salt' => $salt]);


if($hashDois === $hashUm){
echo 'Funcionou';
}

Do not use the above code for obvious security reasons.

Why does the above code work even though it generates twice? Because it is the same salt (the same difficulty and the same algorithm), so the same hash will result, that is how verify_password works.

This is exactly what happens when you use password_verify() , it gets the hash salt and then encrypts the input with the same salt and checks, but logically with side-channel protections and the like.

The difference between BCrypt / PBKDF2 / Argon2i / SCrypt (...) against SHA256, MD5, SHA-1 (...) is precisely that they all have difficulty setting and also a salt, the salt in specific causes same passwords are not equal , see this publication too , as you can easily see above.

How to resolve the problem:

Simple, first a value should be fixed for both sides, it should be "plaintext", not encrypted.

For example:

$tokenPlanoComum = unpack('H*', random_bytes(128))[1];

$tokenSecretoCliente = unpack('H*', random_bytes(32))[1];
$tokenSecretoBanco = password_hash($tokenSecretoCliente,PASSWORD_DEFAULT);

You will save the following information in the database:

$tokenSecretoBanco 
$tokenPlanoComum

You will send the information to the customer:

$tokenPlanoComum
$tokenSecretoCliente

Then to give SELECT you will get via $tokenPlanoComum , in this way, for example:

SELECT * FROM tabela WHERE tokenPlanoComum = "$tokenPlanoComum"

Then after SELECT compare the information that the client sent (from the URL) with the database:

if(password_verify($_GET['tokenSecretoCliente'], $tabela['tokenSecretoBanco'])){
// Tudo certo!
}

Remember, if applicable, set an expiration time, to prevent it from being able to use the same token after a long time.

Why is this efficient?

If there is a flaw in your system that allows you to get the information from the table (eg a Read-Only SQL Injection), one of them is encrypted and only the client is in possession, so you will still be safe since you will need both correct. ;)

Why does this work?

Because there is a common ground where it is unchangeable and will always be the same for both sides.

    
15.05.2017 / 00:55