2

我有一个关于密码哈希的问题。我在http://crackstation.net/hashing-security.htm上找到了一个很棒的教程。这就是我使用以下代码从密码创建哈希的方式:

$hashed_password = create_hash(form_password);

这段代码的问题在于它每次都会为相同的密码创建不同的哈希值。我猜这是因为在密码中添加了随机盐:

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" .
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

因此,由于这个原因,我无法将用户在登录时输入的密码创建的哈希值与从数据库中检索到的哈希值进行比较,因为该哈希值永远不会与存储在数据库中的哈希值相同。我认为可以做到的唯一方法是将盐存储在另一列中,还是我错了?

还有一件事让我很烦。hast 的格式为例如 sha256:1000:u9p+OqAZgVkIBtlTBkr9ZxhFvtt+zjcA:PvhJY+oesrdBeD5pjeXMQ/3wficCU0EG。黑客显然知道这种形式的哈希,所以创建这种哈希的算法对他来说是清楚的。让我们假设数据库已被入侵,并且有数千个这样的哈希码被泄露。这种形式的哈希码不会引发安全问题吗?我想一个简单的 OqAZgVkIBtlTBkr9ZxhFvtt+zjcA:PvhJY+oesrdBeD5pjeXMQ/3wfic 会更好,因为它没有透露任何关于加密机制的信息。

4

4 回答 4

4

相同密码的两个哈希值不匹配的原因是因为结果create_hash()包含随机生成的盐。

要获得相同的哈希,您必须在验证时提供盐。CrackStation.net 提供的代码让这变得超级简单 - 只需将结果原样存储create_hash()在您的数据库中即可。要确认用户输入了正确的密码,请使用

validate_password('provided-password','hash-from-database');

这将返回密码是否正确的布尔值。使用这种方法比编写自己的方法要好,因为它专门用于防止某些提示可能基于返回答案所需的时间而提示正确密码。这是一个小弱点,但无论如何最好避免它,特别是因为提供的功能会为您处理它。

提供的函数为您提供了一个可靠的实现,所以不要过多地弄乱它。散列包括那些额外的细节 - sha256:1000 - 以允许将来更改您的散列而不影响现有用户的登录能力;无论当前方法是什么,它都会简单地使用散列中提供的方法。

至于向潜在的攻击者展示哈希是如何创建的:格式确实显示了有关如何创建的所有内容,但这一点都不重要。攻击者可以很容易地从一两个已知的密码:哈希对中找出使用的方法。比这更重要的是使用一个好的算法。目标是即使有所有细节也很难破解密码,因为默默无闻的安全性很差。

最后,重申一下,您不需要将盐存储在单独的列中,只需将它返回的 70-80 个大字符块单独保留为您的哈希,并让函数为您处理所有事情 - 其他任何事情都是浪费时间和资源

于 2014-08-10T18:31:03.003 回答
4

在此处阅读此维基百科的链接

它解释了更多关于随机盐的使用。关键信息是随机盐存储在与哈希密码相同的数据库中。它仅在用户创建或更改密码时随机创建几次。每当需要身份验证时使用它。

留下有关它用于创建密码哈希的算法的信息,让您可以选择在将来的某个时间更改算法,而不会中断您的用户。如果您决定升级哈希算法,您将等到用户登录。此时您的密码是纯文本的。根据旧算法进行身份验证后,您可以重新散列并将新散列存储在其数据库行中。所有用户可能需要数月或数年才能登录,但一旦登录,他们将获得更好的散列带来的好处。因此,您将发送一封电子邮件,要求他们登录并阅读有关更好安全性的特别新闻(并作为副作用,改进他们的哈希密码)。

这是一个关于密码散列StackOverflow 的有趣讨论:密码存储散列 ...

于 2013-01-25T20:22:16.523 回答
1

要为出色的公认答案添加更多内容:

对哈希进行加盐的目的是让某人不可能带着一大堆预加密的哈希来一个一个地尝试它们。即使您的数据库中有盐,他们也必须针对该盐对每个可能的字典条目进行散列,以成功匹配散列。并且盐每次都需要不同以防止重复输入(他们破解了一个密码,他们拥有与其他用户输入的相同密码)。

至于无法将登录哈希与存储的哈希进行比较,这是故意的:您使用验证功能来检查登录密码与存储的密码,而不是字符串比较功能。

于 2014-01-23T17:48:58.503 回答
1

存储盐,然后将盐添加到密码中,然后将其转换为哈希然后存储。

然后比较密码,您检索盐并将其添加到密码中,将其转换为散列,然后比较两个散列。

(python示例,当我从我的代码中复制代码时,缩进被弄乱了)

def Createpassword():
import random
import hashlib
username = input("type your username")
newpassword = input("type your new password? ")
#adds some salt
b = random.randint(1, 2000000000000)
randomsalt = str(b)

saltedpassword = (newpassword + randomsalt)

#hashes the newpassword

saltedpassword = saltedpassword.encode('utf-8')   
h = hashlib.sha256(saltedpassword)
finsh = h.hexdigest()

#creates file names
saltname = username + "salt.txt"
username = username + ".txt"


#saves the hashedpassword and the salt
text_file = open(username, "w")    
text_file.write(finsh)
text_file.close()
text_file = open(saltname, "w")    
text_file.write(randomsalt)
text_file.close()
print("your new password has been saved")

def EnterPassword():
    trys = 0
    while (trys < 3):
            username = input("type your username: ")
            #takes password input
            password = input("type your password: ")

            #gets file names
            saltname = username + "salt.txt"
            username = username + ".txt"

            #opens salt file
            text_file = open(saltname, "r")
            salt1 = text_file.read(50)
            text_file.close()
            #opens the hashed passwords file
            text_file = open(username, "r")
            correctpassword = text_file.read(500)
            text_file.close()

            #adds the salt to the password input
            saltedpassword = password + salt1


            #hashes the saltedpassword
            saltedpassword = saltedpassword.encode('utf-8') 
            m = hashlib.sha256(saltedpassword)
            hashedpassword = m.hexdigest()

            #compears hashed passwords

            if hashedpassword != correctpassword:
                    trys += 1
                    print("your password or username is incorrect")
            if trys == 3:
                    print("you have been locked out for using to many failed trys")
            if hashedpassword == correctpassword:
                    print ("Password Correct ")
                    #done give access
                    trys = 0
                    break

(我是编程新手,请随时纠正我)

于 2017-03-01T09:41:54.047 回答