CryptContext 哈希如何知道使用什么秘密?

sup*_*ick 8 passlib fastapi

我有以下代码片段:

from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
pwd_context.hash(password)
Run Code Online (Sandbox Code Playgroud)

这里描述的是。

我不明白的是,如果它始终返回相同的散列密码而不考虑另一个 Secret_key 例如散列密码值,这怎么可能是安全的?

Mat*_*ndh 19

您认为它始终返回相同的散列密码而不考虑另一个“秘密”(好吧,这不是真正的秘密)的假设是错误的;pwd_context.hash如果你运行多次,你会看到这个:

>>> from passlib.context import CryptContext
>>>
>>> pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
>>> pwd_context.hash("test")
'$2b$12$0qdOrAMoK7dgySjmNbyRpOggbk.IM2vffMh8rFoITorRKabyFiElC'
>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这两个哈希值并不相同 - 即使给出相同的密码。那么到底发生了什么?

当您没有给出hash明确的盐(您正在谈论的秘密“密钥”)时,将由 为您生成一个盐passlib。值得指出的是,散列与加密不同,因此没有密钥可谈。相反,您会看到salt提到的,这是一个明文值,用于确保相同的密码散列两次会给出不同的结果(因为您实际上是在散列salt + password)。

那么为什么我们会得到两个不同的值呢?这salt是实际 bcrypt 值的前 22 个字符。这些字段用$-分隔,2b表示 bcrypt,12表示 12 轮,下一个字符串是为密码存储的实际结果值(盐 + 结果 bcrypt 哈希)。该字符串的前 22 个字符是纯文本形式的盐。

如果你给 bcrypt 一个盐而不是让它生成一个盐,你可以看到这一点(最后一个字符必须是匹配[.Oeu]某些 bcrypt 实现的预期位填充的字符之一 - passlib 否则会抛出错误或警告 - 其他字符必须是匹配 ) 的正则表达式字符类[./A-Za-z0-9]

>>> pwd_context.hash("test", salt="a"*21 + "e")
'$2b$12$aaaaaaaaaaaaaaaaaaaaaehsFuAEeaAnjmdgkAxYfzHEipCaNQ0ES'
        ^--------------------^
Run Code Online (Sandbox Code Playgroud)

如果我们明确给出相同的哈希值,结果应该是相同的(这就是您稍后验证密码的方式):

>>> pwd_context.hash("test", salt="a"*21 + "e")
'$2b$12$aaaaaaaaaaaaaaaaaaaaaehsFuAEeaAnjmdgkAxYfzHEipCaNQ0ES'
>>> pwd_context.hash("test", salt="a"*21 + "e")
'$2b$12$aaaaaaaaaaaaaaaaaaaaaehsFuAEeaAnjmdgkAxYfzHEipCaNQ0ES'
Run Code Online (Sandbox Code Playgroud)

前面的哈希值也是如此:

>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
        ^--------------------^
Run Code Online (Sandbox Code Playgroud)

这是实际生成的盐,然后与 一起使用test来创建实际的哈希值:

>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
                              ^-----------------------------^
Run Code Online (Sandbox Code Playgroud)

那么,当每个人都清楚地看到这种盐时,我们为什么要使用它呢?它使得不可能只扫描已知哈希值的哈希值列表 - 因为test在您的列表中将具有与test您要比较的列表中不同的值(因为不同的盐),您必须实际测试猜测的密码及其盐,并通过哈希算法运行它们。bcrypt明确设计为使该过程需要时间,因此您将花费更长的时间尝试破解密码,而不仅仅是扫描 2 亿个密码的列表并在数据库中搜索已知的哈希值。

它还将确保具有相同密码的两个用户不会收到相同的密码哈希值,因此您无法通过查找在多个用户之间重复的密码哈希值来快速确定弱密码(或尝试确定两个用户是否相同)同一个人,因为他们有相同的密码)。

那么当计算机变得更快时你会做什么呢?您增加12参数 - the rounds- 这会增加散列算法的运行时间,希望在更长的时间内保持更安全(您可以尝试使用rounds参数 to passlib.hash)。