CryptContext 哈希如何知道使用什么秘密?
How does CryptContext hashing know what secret to use?
我有以下代码片段:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
pwd_context.hash(password)
描述的是here。
我不明白的是,如果一直 returns 相同的散列密码而不考虑另一个 secret_key 来散列密码值,这怎么可能安全?
您假设它一直 returns 相同的散列密码而不考虑另一个“秘密”(嗯,这不是真正的秘密)是错误的;如果你 运行 pwd_context.hash
多次你会看到这个:
>>> from passlib.context import CryptContext
>>>
>>> pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
>>> pwd_context.hash("test")
'b[=10=]qdOrAMoK7dgySjmNbyRpOggbk.IM2vffMh8rFoITorRKabyFiElC'
>>> pwd_context.hash("test")
'b$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
如您所见,这两个哈希值并不相同 - 即使给定相同的密码。那么到底发生了什么?
当您不给 hash
明确的盐(您正在谈论的秘密“密钥”)时 one will be generated for you by passlib
。值得指出的是,散列与加密不同,因此没有 key 可谈。相反,您会看到提到的 salt
,这是一个明文值,用于确保相同的密码经过两次哈希处理后会产生不同的结果(因为您实际上是在对 salt + password
进行哈希处理)。
那么为什么我们会得到两个不同的值呢? salt
是实际 bcrypt 值的前 22 个字符。这些字段由 $
分隔 - 2b
表示 bcrypt,12
表示 12 轮,下一个字符串是为密码存储的实际结果值(salt + resulting bcrypt hash)。此字符串的前 22 个字符是散列。
如果你给 bcrypt 一个 salt 而不是让它生成一个 salt,你就会看到这一点(我们将忽略这里可能出现的关于小填充的警告,但为了展示这个概念):
>>> pwd_context.hash("test", salt="a"*22)
'b$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
^-------------------^
如果我们明确给出相同的哈希值,结果应该是相同的(这也是您稍后验证密码的方式):
>>> pwd_context.hash("test", salt="a"*22)
'b$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
>>> pwd_context.hash("test", salt="a"*22)
'b$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
前面的哈希也是如此:
>>> pwd_context.hash("test")
'b$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^-------------------^
这是实际生成的盐,然后与 test
一起使用来创建实际的散列:
>>> pwd_context.hash("test")
'b$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^------------------------------^
那么,当每个人都清楚地看到这种盐时,我们为什么要使用它呢?这使得仅扫描已知散列的散列列表变得不可能 - 因为列表中的 test
将具有与您正在比较的列表中的 test
不同的值(因为不同盐),您必须实际 测试猜测的密码及其盐,并通过散列算法运行 测试它们。 bcrypt
明确设计为使该过程需要时间,因此与仅扫描 2 亿个密码列表并在数据库中搜索已知哈希相比,您尝试破解密码所花费的时间要长得多。
当计算机变得更快时,您会怎么做?您增加 12
参数 - rounds
- 这会增加散列算法的 运行 时间,希望在更长时间内保持更安全(您可以试验 rounds
参数以passlib.hash
).
我有以下代码片段:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
pwd_context.hash(password)
描述的是here。
我不明白的是,如果一直 returns 相同的散列密码而不考虑另一个 secret_key 来散列密码值,这怎么可能安全?
您假设它一直 returns 相同的散列密码而不考虑另一个“秘密”(嗯,这不是真正的秘密)是错误的;如果你 运行 pwd_context.hash
多次你会看到这个:
>>> from passlib.context import CryptContext
>>>
>>> pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
>>> pwd_context.hash("test")
'b[=10=]qdOrAMoK7dgySjmNbyRpOggbk.IM2vffMh8rFoITorRKabyFiElC'
>>> pwd_context.hash("test")
'b$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
如您所见,这两个哈希值并不相同 - 即使给定相同的密码。那么到底发生了什么?
当您不给 hash
明确的盐(您正在谈论的秘密“密钥”)时 one will be generated for you by passlib
。值得指出的是,散列与加密不同,因此没有 key 可谈。相反,您会看到提到的 salt
,这是一个明文值,用于确保相同的密码经过两次哈希处理后会产生不同的结果(因为您实际上是在对 salt + password
进行哈希处理)。
那么为什么我们会得到两个不同的值呢? salt
是实际 bcrypt 值的前 22 个字符。这些字段由 $
分隔 - 2b
表示 bcrypt,12
表示 12 轮,下一个字符串是为密码存储的实际结果值(salt + resulting bcrypt hash)。此字符串的前 22 个字符是散列。
如果你给 bcrypt 一个 salt 而不是让它生成一个 salt,你就会看到这一点(我们将忽略这里可能出现的关于小填充的警告,但为了展示这个概念):
>>> pwd_context.hash("test", salt="a"*22)
'b$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
^-------------------^
如果我们明确给出相同的哈希值,结果应该是相同的(这也是您稍后验证密码的方式):
>>> pwd_context.hash("test", salt="a"*22)
'b$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
>>> pwd_context.hash("test", salt="a"*22)
'b$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
前面的哈希也是如此:
>>> pwd_context.hash("test")
'b$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^-------------------^
这是实际生成的盐,然后与 test
一起使用来创建实际的散列:
>>> pwd_context.hash("test")
'b$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^------------------------------^
那么,当每个人都清楚地看到这种盐时,我们为什么要使用它呢?这使得仅扫描已知散列的散列列表变得不可能 - 因为列表中的 test
将具有与您正在比较的列表中的 test
不同的值(因为不同盐),您必须实际 测试猜测的密码及其盐,并通过散列算法运行 测试它们。 bcrypt
明确设计为使该过程需要时间,因此与仅扫描 2 亿个密码列表并在数据库中搜索已知哈希相比,您尝试破解密码所花费的时间要长得多。
当计算机变得更快时,您会怎么做?您增加 12
参数 - rounds
- 这会增加散列算法的 运行 时间,希望在更长时间内保持更安全(您可以试验 rounds
参数以passlib.hash
).