7

在阅读了有关 salts 密码哈希的信息后,我想为我正在构建的站点的管理区域实现一个简单的版本。

如果您有任何很好的代码链接可以很好地实现这个想法,如果您能分享,我将不胜感激。

谢谢,

4

8 回答 8

6

注册过程:用户输入密码。系统从随机数据中生成一个盐值(可以是时间和 PID 或其他东西的哈希值)。系统生成密码和盐值的哈希值,并将这两者存储在注册表中。

登录过程:用户输入密码。系统从数据库中提取盐值并将其与密码进行哈希处理,并将其与注册期间放入数据库的哈希密码值进行比较。

明文密码永远不会存储在数据库中。客户端永远不会看到盐值。

于 2010-06-08T16:07:45.033 回答
3
function encodePwd($salt, $string) {
   return sha1( $salt . $string );
}

不过考虑一下盐随机化。专门的密码编码。

如果我有“随机”的盐和“复杂”的密码,我的 sha1 将是

e55ec45f2873a04d2b888a5f59dd3f9d3bb25329

存储在数据库中。我想检查一下。

因此,当用户向我提供“复杂”密码时,我在其前面标记“随机”并对其进行编码以获得相同的哈希值。如果它们相等,那么 bazinga!我准备好了。

但如果那是随机的呢?

存储时的盐:“随机”

SHA1: e55ec45f2873a04d2b888a5f59dd3f9d3bb25329

用户放入时加盐:“apple”

SHA1: e07b207d77a0bd27d321552fc934b186559f9f42

我将如何匹配这些?

如果您正在寻找一种更安全的方法,请使用您拥有的数据,并且这些数据是不变的,例如用户的用户名或 id 或其他东西(最好是不会改变的东西)。你需要一个可以依赖的模式。

用户名会很好用(如果他们更改了用户名,您必须确保更新密码)这样身份验证可能看起来像

`WHERE `username` = '&username' AND `password` = '" . encodePwd( $username, $password ) . "'"`

function encodePwd( $username, $password) {
   // maybe modify username on a non-random basis? - like
   // $username = sha1( substr($username, 2)); // assuming usernames have a min-length requirement
   return sha1( $username  . $password ) ;
}
于 2010-06-08T15:57:00.977 回答
3

好吧,这就是我要做的:

function makeToken($length = 16) {
    if ($length > 16) {
        $ret = '';
        while ($length > 0) {
            $ret .= makeToken(16);
            $length -= 16;
        }
        if ($length < 0) {
            $ret = substr($ret, 0, $length);
        }
        return $ret;
    }
    $stub = '';
    for ($i = 0; $i < 100; $i++) {
        $stub .= chr(mt_rand(1, 254));                
    }
    $hash = sha1($stub);
    $hashLen = strlen($hash);
    $ret = '';
    for ($i = 0; $i < $length; $i++) {
        $ret .= $hash[mt_rand(0, $hashLen - 1)];
    }
    return $ret;
}

function makeSaltedHash($string, $salt = '') {
    if (empty($salt)) { 
        $salt = makeToken();
    }
    $hash = '';
    for ($i = 0; $i < 200; $i++) {
        $hash = sha1($hash . $salt . $string);
    }
    return $hash . ':' . $salt;
}

function verifySaltedHash($string, $hash) {
    if (strpos($string, ':') === false) return false;
    list ($base, $salt) = explode(':', $hash);
    $test = makeSaltedHash($string, $salt);
    return $test === $hash;
}

道理是这样的:

首先,生成一个随机盐(这将始终返回一个十六进制字符串,因此它可以用于令牌等)。然后循环一个哈希函数(在本例中为 sha1)超过 1 次。这使得生成彩虹表变得更加昂贵(在这种情况下是成本的 200 倍),而生成的费用相对较少。

用法:

要生成哈希:

$hash = makeSaltedHash($password);

要验证哈希:

$bool = verifySaltedHash($password, $savedHash);

要生成令牌(CSRF 保护、session_id 等),您可以通过以下几种方式进行:

固定长度:

$token = makeToken(32);

随机长度:

$token = makeToken(mt_rand(64,128));

编辑:在散列函数中增加了对 sha1 的重复。

于 2010-06-08T16:17:00.440 回答
2

我没有可用代码的链接,但我过去所做的是生成随机盐 -$salt = rand(1,1000000000);并将其保存在会话中。我将该盐传递给登录页面,然后使用 JavaScript 创建一个盐 + 密码的 SHA 哈希,该哈希是提交的,而不是明文密码。由于盐存储在会话中,因此我可以使用它来查看登录哈希是否与存储在数据库中的盐 + 密码哈希匹配。

于 2010-06-08T16:03:34.690 回答
1

如果您需要真正安全的哈希,请使用Portable PHP hashing framework

我还推荐本月的 PHP 安全文章,该文章广泛涉及密码散列和散列的安全性。

于 2010-06-08T16:11:51.830 回答
0

有很多方法可以创建盐串,但我认为你不需要过多考虑盐的强度。

我像这样散列密码

$hash = sha1(strlen($password) . md5($password) . $salt);

我认为它是速度和“安全性”之间的最佳表现。

function salt($lenght = 9) {
    $numbers = '0123456789';
    $chars = 'qwertzuiopasdfghjklyxcvbnm';

    $password = '';
    $alt = time() % 2;
    for ($i = 0; $i < $length; $i++) {
        if ($alt == 1) 
        {
            $password .= $chars[(rand() % strlen($chars))];
            $alt = 0;
        } else 
        {
            $password .= $numbers[(rand() % strlen($numbers))];
            $alt = 1;
        }
    }
    return $password;
}
于 2010-06-08T16:09:52.133 回答
0

代码很简单,dan heberden 已经提供了。

盐只是在生成哈希之前附加或附加到密码的一段文本。例如,如果您的密码是 'password' 而 salt 是 'salt',那么哈希值将hashFunction('saltpassword')不是hashFunction('password').

盐通常用于避免彩虹密码破解 - 这是根据哈希密码检查大量密码及其哈希值的地方。例如,在上面的示例中,假设有一个对应于 的哈希 123456 hashFunction('password'),如果攻击者知道您的哈希是 123456,那么他们知道您的密码是“密码”。

你的盐应该是一个随机的字母和数字串——例如kjah!!sdf986。某人拥有包含 kjah!!sdf986password 的彩虹表的可能性非常小,因此即使有人获得了您的散列密码,那也没什么用。

但是,您显然需要每次都使用相同的盐,或者至少存储盐和密码。因为如果您每次都选择随机盐,那么您的散列盐+密码可能会不一样:D

于 2010-06-08T16:11:29.460 回答
0

你可以使用内置crypt(...) 功能吗?

... 用法 ...

crypt('rasmuslerdorf', '$1$rasmusle$')

... 结果 ...

MD5: $1$rasmusle$rISCgZzpwk3UhDidwXvin0

...文档中提供了更多示例和其他哈希方法。

于 2010-06-08T16:24:25.823 回答