散列和盐值的概念

9
我正在开发一个小型的Web应用程序,用于内部用户身份验证。一旦用户通过身份验证,我的Web应用程序就会将一些信息(如userID和人名)传递给第三方Web应用程序。第三方开发人员建议我们对这些值进行哈希和盐处理。
请原谅我的无知,那到底是什么意思?
我使用Java编写该应用程序。因此,我的计划是使用Apache Commons Digest Utils SHA512对userID、人名和一些Math.random()值进行哈希,并将该哈希字符串与userID和人名一起传递。
这是标准做法吗? 我应该将盐也传递给第三方,对吗?

我很高兴看到这个问题的许多回答都回答了标题并回答了不相关的问题“什么是加盐密码?”。 - dimo414
6个回答

14

通常用盐来安全地存储密码的哈希值。对密码进行哈希以便于存储或通信(以使其不能被他人读取)会容易受到使用彩虹表进行解码的攻击。现在,当您将一个随机字符串添加到密码中,但将该字符串与哈希一起存储时,这变得更加困难。计算这个新哈希的方法如下:

hash(password + salt)

甚至可以

hash(hash(password) + salt)

为了安全地登录第三方网站,可以发送用户ID、加盐的哈希值(来自上面)以及所使用的盐(如果未提供)。根据该网站存储密码的方式,您可以自行生成盐,也可以向其请求盐。

一种选项是首先将用户ID发送到网站,然后让其响应盐,然后将hash(password+salt))发送回网站。


我原本以为第三方网站即使有正确的会话ID也无法访问我的会话对象,但也许我错了? - Avanst
啊,抱歉,我误解了你的问题。我会编辑我的回答。 - Marc
@Avanst - 这取决于会话是否存储在用户的浏览器中(“无状态服务器”,用户可以看到会话)还是以某种方式存储在服务器上(“非无状态”,用户无法看到会话)。 - Amy B
这回答了我的问题,如果我表达不够清楚,对不起,但非常感谢 :) - Avanst
3
哈希输出是随机字节,而不是“字母/数字”。没有发生重要削弱。 - President James K. Polk
显示剩余3条评论

8

在Java中,您可以这样做:

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.RandomStringUtils;

/**
 * SHA1-hash the password with the user's salt.
 *
 * @param password
 */
public void setPassword(String password)
{
    if (password.equals(this.password))
    {
        return;
    }

    if (passwordSalt == null || passwordSalt.equals(""))
    {
        passwordSalt = RandomStringUtils.randomAscii(20);
    }

    this.password = DigestUtils.shaHex(password + passwordSalt);
}

/**
 * Check if a given password is correct.
 *
 * @param givenPassword
 * @return True is correct, else false.
 */
public boolean checkPassword(String givenPassword)
{
    return (password.equals(DigestUtils.shaHex(givenPassword + passwordSalt)));
}

那么密码即使被黑客窃取数据库,也无法读取。

你需要返回密码盐,最好附带一个getter函数。 - President James K. Polk
使用 apache commons codec lib 得分加一!从 apache.org 下载 commons-codec-1.9.jar - Kai Burghardt

3
只是提醒一下,有些关于如何处理盐的信息是错误的。将盐储存是可以的,并且也很正常。每个密码都应该有自己的盐,以明文方式存储在一起。这样做的目的是使得已经窃取了你的哈希密码数据库的人,使用预先计算好的哈希表来解密它会变得更加困难。
至于是否应该向第三方发送盐,请提供更多信息。进行身份验证期间获取客户端提供的密码,对其进行哈希并与预先哈希版本进行比较的任何人都需要盐,以便客户端提供的认证密码可以被哈希为完全相同的结果。请注意保留HTML标记。

1
一旦用户通过身份验证,我的Web应用程序会将一些信息(如userID和人名)传递给第三方Web应用程序。第三方开发人员建议我们对这些值进行哈希和加盐处理。
这听起来不太对。哈希是单向操作。您无法从哈希的结果中推断出明文。
我计划使用userID、人名和一些Math.random()值作为盐进行哈希。
对于任何给定的明文,您需要使用相同的盐,否则生成的哈希将不同。因此,如果您要使用随机或生成的盐,则需要将其与密码哈希一起存储。
使用SHA-256或SHA-512是可以的,这也是NIST建议的做法。

2
你的意思是对于任何给定的明文,你需要使用相同的盐吗?盐的整个意义在于,相同的明文可以有数万亿个不同的*hash(plaintext + salt)结果,从而使“彩虹表”攻击变得不可能。例如,在Unx系统上,你可以有两个用户选择相同的密码,但是那个密码将具有两个不同的哈希值,因为使用了不同的盐(保存在哈希密码旁边)。 - NoozNooz42
1
我认为你误解了他的意思 - 如果盐不同,即使是相同的明文,生成的哈希值也会不同。 - dimo414

1

我建议你在使用这个第三方应用程序时,尽可能找到更多信息或一些示例。根据你所描述的情况,这似乎不是常见的做法,而且基于你所说的也没有太多意义。

你在程序中对用户进行身份验证(有几个答案似乎正在解决这个问题,是的,你应该将用户密码存储为加盐哈希值,但这是另一个问题),然后,在验证他们之后,将一些信息传递给这个第三方应用程序。现在,这取决于这个应用程序需要做什么/知道什么。例如,如果它需要知道userID,那么在提交之前就不能对其进行哈希/加盐,因为该应用程序将永远无法获取原始的userID。另一方面,如果该应用程序只需要某种标识符来识别请求,并且将userID + userName哈希化只是一个建议,则这是有意义的,你基本上为第三方应用程序生成了一个用户唯一但不可解码的字符串,作为会话密钥。

如果他们试图让你采取第二种路线,这是一种有点奇怪(并且不太安全)的处理请求的方式,但在我看来还可以接受。

就像我说的那样,看看能否找到一些例子,或者如果你想在这里发布有关该应用程序的更多信息,我们可以自己看一下。


0

盐的整个意义在于使使用所谓的“彩虹表”进行攻击变得不可行(从概率角度来看:如果你采用足够大的哈希值,则事实上将不可能预计算彩虹表)。

http://en.wikipedia.org/wiki/Rainbow_table

不要只是对一个哈希值(a)进行哈希处理并存储该哈希值:

:460526e74fd6a25b525e642db2f756a4:

你需要执行hash(a + salt)操作,并且存储哈希值和盐值(盐值可以随机选择):

:cdd5bc3f05f6a76f6c82af728b2c555c:346884e6e35be:

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