在PHP中更新旧存储的md5密码以提高安全性 [英] Update old stored md5 passwords in PHP to increase security

查看:191
本文介绍了在PHP中更新旧存储的md5密码以提高安全性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我有一个存储md5密码的数据库,几年前,这被认为比现在更安全一点,而且密码需要更安全。

At the moment I have a database with md5 passwords stored, a few years back this was considered a little more secure than it is now and it's got to the point where the passwords need to be more secure.

我已经阅读了很多有关 crypt的帖子 md5 哈希 bcrypt 等,并考虑使用沿着以下内容的东西来保护密码比现在更好。

I've read a lot of posts on here about crypt, md5, hash, bcrypt, etc and have come to consider using something along the lines of the following to 'secure' the passwords better than they are now.

我将使用 hash(sha512和两种盐,第一个盐将是一个存储在文件中的网站宽盐,如.htaccess,并为每个用户创建第二个盐。

I will use a combination of hash("sha512" and two salts, the first salt will be a site wide salt stored in a file such as .htaccess and the second salt will be created for each user.

这里是一个例子,

.htaccess

.htaccess

SetEnv SITEWIDE_SALT NeZa5Edabex?26Y#j5pr7VASpu$8UheVaREj$yA*59t*A$EdRUqer_prazepreTr

example.php

example.php

$currentpassword = //get password

$pepper = getenv('SITEWIDE_SALT');
$salt = microtime().ip2long($_SERVER['REMOTE_ADDR']);

$saltpepper = $salt.$pepper;

$password = hash("sha512", md5($currentpassword).$saltpepper);

盐显然需要存储在单独的表中,以便检查未来插入的登录密码,用户永远不可能看到。你认为这是一个足够的方法来解决这个问题吗?

The salt would obviously need to be stored in a separate table to allow checking of future inserted login passwords but it would never be possible for a user to see. Do you think this is a sufficient way to go about this?

推荐答案

>

Ok, let's go over a few points here


  1. 您在 $ salt 中的内容不是盐。这是确定性的(意味着根本就没有随机性)。如果您想要盐,请使用 mcrypt_create_iv($ size,MCRYPT_DEV_URANDOM) 或其他实际随机熵的来源。关键是它应该是独一无二的。请注意,它不需要加密安全随机的...在绝对最差的情况下,我会这样做:

  1. What you have in $salt is not a salt. It's deterministic (meaning that there is no randomness in there at all). If you want a salt, use either mcrypt_create_iv($size, MCRYPT_DEV_URANDOM) or some other source of actual random entropy. The point is that it should be both unique and random. Note that it doesn't need to be cryptographically secure random... At absolute worst, I'd do something like this:

function getRandomBytes($length) {
    $bytes = '';
    for ($i = 0; $i < $length; $i++) {
        $bytes .= chr(mt_rand(0, 255));
    }
    return $bytes;
}


  • As @ Anony-Mousse表示, strong>将一个哈希函数的输出提供给另一个哈希函数,而不会将原始数据重新附加到该函数。相反,使用适当的迭代算法,例如 PBKDF2 PHPASS CRYPT_BLOWFISH ($ 2a $)。

  • As @Anony-Mousse indicated, never feed the output of one hash function into another without re-appending the original data back to it. Instead, use a proper iterative algorithm such as PBKDF2, PHPASS or CRYPT_BLOWFISH ($2a$).

    我的建议是使用 crypt with blowfish,因为它是目前最适用于PHP的:

    My suggestion would be to use crypt with blowfish, as it's the best available for PHP at this time:

    function createBlowfishHash($password) {
        $salt = to64(getRandomBytes(16));
        $salt = '$2a$10$' . $salt;
        $result = crypt($password, $salt);
    }
    

    然后使用这样的方法进行验证:

    And then verify using a method like this:

    function verifyBlowfishHash($password, $hash) {
        return $hash == crypt($password, $hash);
    }
    

    (注意 to64 是定义好的方法这里)。你也可以使用 str_replace('+','。',base64_encode($ salt)); ...

    (note that to64 is a good method defined here). You could also use str_replace('+', '.', base64_encode($salt));...

    我还建议你阅读以下两个:

    I'd also suggest you read the following two:

    所以我意识到我的答案没有解决原始问题的迁移方面。所以这里我将如何解决它。

    Ok, so I realize that my answer did not address the migration aspect of the original question. So here's how I would solve it.

    首先,构建一个临时函数,从原始的md5哈希创建一个新的blowfish哈希,随机盐和一个前缀,以便我们可以稍后检测:

    First, build a temporary function to create a new blowfish hash from the original md5 hash, with a random salt and a prefix so that we can detect this later:

    function migrateMD5Password($md5Hash) {
        $salt = to64(getRandomBytes(16));
        $salt = '$2a$10$' . $salt;
        $hash = crypt($md5Hash, $salt);
        return '$md5' . $hash;
    }
    

    现在,通过此功能运行所有现有的md5哈希值,并将结果保存在数据库。我们把自己的前缀放在我们可以检测到原始密码,并添加额外的md5步骤。所以现在我们都被迁移了。

    Now, run all the existing md5 hashes through this function and save the result in the database. We put our own prefix in so that we can detect the original password and add the additional md5 step. So now we're all migrated.

    接下来,创建另一个函数来验证密码,如果需要,使用新的哈希更新数据库:

    Next, create another function to verify passwords, and if necessary update the database with a new hash:

    function checkAndMigrateHash($password, $hash) {
        if (substr($hash, 0, 4) == '$md5') {
            // Migrate!
            $hash = substr($hash, 4);
            if (!verifyBlowfishHash(md5($password), $hash) {
                return false;
            }
            // valid hash, so let's generate a new one
            $newHash = createBlowfishHash($password);
            saveUpdatedPasswordHash($newHash);
            return true;
        } else {
            return verifyBlowfishHash($password, $hash);
        }
    }
    

    这是我建议的几个原因:

    This is what I would suggest for a few reasons:


    1. 它会立即从您的数据库中将 md5()散列出来。

    2. 最终(每个用户的下一次登录)将哈希更新为一个更好的选择(一个很好理解)。

    3. 在代码中很容易遵循。 li>
    1. It gets the md5() hashes out of your database immediately.
    2. It eventually (next login for each user) updates the hash to a better alternative (one that's well understood).
    3. It's pretty easy to follow in code.

    回答评论:


    1. 盐不需要随机 - 我指示您 RFC 2898 - 密码基于密码学的。即,第4.1节。我引用:

    1. A salt doesn't need to be random - I direct you to RFC 2898 - Password Based Cryptography. Namely, Section 4.1. And I quote:


    如果不关心多个使用之间的交互
    的同一个键(或那个的前缀)密钥)与
    的加密和身份验证技术支持
    给定的密码,那么盐可以随机生成,
    不需要被对方的特定格式检查
    接受盐。它应该是至少八个八位字节(64
    位)长。

    If there is no concern about interactions between multiple uses of the same key (or a prefix of that key) with the password- based encryption and authentication techniques supported for a given password, then the salt may be generated at random and need not be checked for a particular format by the party receiving the salt. It should be at least eight octets (64 bits) long.

    另外,


    注意。如果随机数生成器或伪随机生成器不是
    可用,则生成盐的确定性替代(或
    是其随机部分)是将基于密码的密钥导出
    函数应用于密码和要处理的消息M.

    Note. If a random number generator or pseudorandom generator is not available, a deterministic alternative for generating the salt (or the random part of it) is to apply a password-based key derivation function to the password and the message M to be processed.

    一个PseudoRandom生成器是可用的,所以为什么不使用它?

    A PseudoRandom Generator is available, so why not use it?

    您的解决方案与bcrypt相同吗?我实际上找不到很多关于bcrypt的文档? - 我会假设你已经阅读了 bcrypt维基百科文章,并尝试更好地解释。

    Is your solution the same as bcrypt? I can't find much documentation on what bcrypt actually is? - I'll assume that you already read the bcrypt Wikipedia Article, and try to explain it better.

    BCrypt基于Blowfish块密码。它采用密码的密钥调度设置算法,并使用它来对密码进行哈希处理。它的好处在于,Blowfish的设置算法被设计为非常昂贵(这是使得河豚如此强大的密码的一部分)。基本过程如下:

    BCrypt is based off the Blowfish block cipher. It takes the key schedule setup algorithm from the cipher, and uses that to hash the passwords. The reason that it is good, is that the setup algorithm for Blowfish is designed to be very expensive (which is part of what makes blowfish so strong of a cypher). The basic process is as follows:


    1. 一个18元素数组(称为P框,大小为32位)通过使用预定的静态值初始化阵列来使用维度阵列(称为S盒,每个具有256个条目,每个具有8个位)。另外,64位状态被初始化为全0。

    1. A 18 element array (called P boxes, 32 bits in size) and 4 2-dimensional arrays (called S boxes, each with 256 entries of 8 bits each) are used to setup the schedule by initializing the arrays with predetermined static values. Additionally, a 64 bit state is initialized to all 0's.

    传入的键是XOred,所有18个P框按顺序旋转,如果它也是

    The key passed in is XOred with all 18 P boxes in order (rotating the key if it's too short).

    然后,P框用于加密先前初始化的状态。

    The P boxes are then used to encrypt the state that was previously initialized.

    步骤3生成的密文用于替换P1和P2(P数组的前2个元素)。

    The ciphertext produced by step 3 is used to replace P1 and P2 (the first 2 elements of the P array).

    重复步骤3 ,结果放在P3和P4中。这一直延续到P17和P18。

    Step 3 is repeated, and the result is put in P3 and P4. This continues until P17 and P18 are populated.

    这是Blowfish密码的关键派生。 BCrypt修改为:

    That's the key derivation from the Blowfish Cipher. BCrypt modifies that to this:


    1. 64位状态被初始化为加密版本的盐。

    相同

    然后使用P框加密(状态

    The P boxes are then used to encrypt the (state xor part of the salt) that was previously initialized.

    相同

    相同

    然后使用结果设置对密码进行64次加密。这是BCrypt返回的。

    The resulting setup is then used to encrypt the password 64 times. That's what's returned by BCrypt.

    这一点很简单:这是一个非常昂贵的算法,需要大量的CPU时间。

    The point is simple: It's a very expensive algorithm that takes a lot of CPU time. That's the real reason that it should be used.

    我希望清除这些东西。

    这篇关于在PHP中更新旧存储的md5密码以提高安全性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆