如何在 PHP 中解密密码哈希?

25

我需要解密一个密码。这个密码是用password_hash函数加密的。

$password = 'examplepassword';
$crypted = password_hash($password, PASSWORD_DEFAULT);

现在,假设$crypted已经存储在一个数据库中(有一个“用户”表,包括用户名、密码等),我需要进行登录: 我必须检查用户输入的密码是否与存储在数据库中的加密密码匹配。

以下是SQL代码...

$sql_script = 'select * from USERS where username="'.$username.'" and password="'.$inputpassword.'"';

......但是$inputpassword没有被加密,所以它与存储在用户表密码字段中的内容不相等......

那么,在使用password_hash之后还有解密函数吗?还是我应该更改我的加密方法?或者还有其他方法?


6
password_verify() 是一个函数名,用于验证密码是否和已存储的哈希值匹配。 - Funk Forty Niner
13
无法解密。散列是一种单向函数。将用户提供的密码进行散列,然后查看散列值是否匹配。 - user1864610
1
仍然无法解决多个输入匹配同一哈希的问题。 - akuzminsky
15
哈希函数就像肉磨机一样。牛变成了肉,但你无法通过肉来恢复出牛。 - Marc B
1
强制性的Security.SE链接:https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords - Perseids
显示剩余6条评论
5个回答

38

Bcrypt是一种单向哈希算法,您无法解密哈希值。使用password_verify来检查密码是否与存储的哈希值匹配:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

针对你的情况,只使用用户名来运行SQL查询:

$sql_script = 'SELECT * FROM USERS WHERE username=?';

使用与上面示例类似的代码在PHP中进行密码验证。

您构建查询的方式非常危险。如果不正确地对输入进行参数化,则代码将容易受到SQL注入攻击。请参阅此Stack Overflow答案以了解如何防止SQL注入。


@user2864740 在我的回答中添加了一条注释。我无法建议更好的查询,因为我不知道 OP 是否使用 mysqli、PDO 或某种 ORM。 - Gergo Erdosi
谢谢您添加注释(链接也很好)- 我总是建议使用占位符,但那是另一个问题 :| - user2864740
1
然而,考虑到有多少代码只是被复制粘贴而没有太多考虑,那个警告实在太小了。 - Perseids
2
你可能会遇到严重的问题。为了保持清醒,应该是username=? - tadman

5

密码不能被解密,否则会对用户造成漏洞。因此,您可以简单地使用password_verify()方法来比较密码。

if(password_verify($upass, $userRow['user_pass'])){
     //code for redirecting to login screen }

在这里,$upass 是用户输入的密码,而 $userRow['user_pass'] 则是数据库中的 user_pass 字段,该字段已经通过 password_hash() 函数进行了加密。


1

I need to decrypt a password. The password is crypted with password_hash function.

$password = 'examplepassword';
$crypted = password_hash($password, PASSWORD_DEFAULT);
我不清楚您是否需要使用password_verify,还是试图未经授权地访问应用程序或数据库。其他人已经谈到了password_verify,这里是您如何获取未经授权的访问权限。当坏人试图访问系统时,他们经常这样做。
首先,创建一个明文密码列表。由于像Adobe这样的公司大规模数据泄露,明文列表可以在许多地方找到。对列表进行排序,然后取前10,000或100,000个左右。
其次,创建一个摘要密码列表。只需加密或哈希密码即可。根据上面的代码,看起来没有使用盐(或者是固定盐)。这使得攻击非常容易。
第三,对于列表中的每个摘要密码,执行选择以尝试找到正在使用该密码的用户:
$sql_script = 'select * from USERS where password="'.$digested_password.'"'

第四,利润。

因此,与其选择一个用户并尝试破解他们的密码,坏人会选择一个常见密码并尝试找到正在使用它的用户。很可能坏人会得手...

由于坏人会做这些事情,所以最好不要让用户选择常见密码。在这种情况下,请查看ProCheck、EnFilter或Hyppocrates(等)库。它们是拒绝错误密码的过滤库。ProCheck可以实现非常高的压缩率,并且可以将数百万个单词密码列表消化成30KB的数据文件。


我不认为OP试图黑客任何东西,而且,你必须在你试图暴力破解的服务器上拥有管理员权限。 - Leo Wilson
@LeoWilson - 他想要找回密码。仅凭管理员身份是不够的,因为密码已经被哈希处理过了。 - jww

1
使用 password_verify() 函数。
if (password_vertify($inputpassword, $row['password'])) {
  print "Logged in";
else {
    print "Password Incorrect";
}

-2

看起来有人终于创建了一个解密password_hash的脚本。 看看这个:https://pastebin.com/Sn19ShVX

<?php
error_reporting(0);

# Coded by L0c4lh34rtz - IndoXploit

# \n -> linux
# \r\n -> windows
$list = explode("\n", file_get_contents($argv[1])); # change \n to \r\n if you're using windows
# ------------------- #

$hash = '$2y$10$BxO1iVD3HYjVO83NJ58VgeM4wNc7gd3gpggEV8OoHzB1dOCThBpb6'; # hash here, NB: use single quote (') , don't use double quote (")

if(isset($argv[1])) {
    foreach($list as $wordlist) {
        print " [+]"; print (password_verify($wordlist, $hash)) ? "$hash -> $wordlist (OK)\n" : "$hash -> $wordlist (SALAH)\n";
    }
} else {
    print "usage: php ".$argv[0]." wordlist.txt\n";
}
?>

2
  1. 那不是解密,而是暴力攻击。
  2. 试一下,在100,000个password_hash加密的密码上计时。
  3. 这种方法很常见,而password_hash的目的是消耗大量CPU时间,以使暴力攻击变得非常耗时。这是我们能做到的最好的防护措施。
- zaph
是的,这不是解密器。但如果他们在自己的电脑/服务器上进行操作,这并不是暴力破解攻击... 这取决于密码的大量收集(数据库、单词列表),就像他们对许多MD5数据库所做的那样。 - Cholis
1
  1. 这仍然是一种暴力攻击方法,无论在何处或由谁实施都没有区别。
  2. 它不像MD5彩虹表攻击,因为password_hash中涉及到一个随机种子,所以必须对每个尝试的密码进行password_verification计算。
  3. 成本应该选择得使得password_verification大约需要100毫秒,比通常可以在少于0.01毫秒内计算出来的密码的MD5慢得多,因此,在相同类CPU上,password_verification比MD5慢了大约100,000倍。
- zaph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接