我有以下代码片段:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
pwd_context.hash(password)
此处对此进行了描述。
我不明白的是,如果它一直返回相同的散列密码,而不考虑另一个secret_key来散列密码值,这怎么可能是安全的?
您的假设是,它始终返回相同的哈希密码,而不考虑另一个"秘密";(嗯,这并不是真正的秘密(是错误的;如果你多次运行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'
正如你所看到的,这两个散列是不一样的——即使被赋予相同的密码。那么到底发生了什么呢?
当你不给hash
一个显式的salt(你所说的秘密"密钥"(时,passlib
会为你生成一个。值得指出的是,哈希与加密不同,因此没有密钥可谈。相反,您会看到提到的salt
,这是一个明文值,用于确保对同一密码进行两次哈希处理会得到不同的结果(因为您实际上是在对salt + password
进行哈希处理(。
那么,为什么我们会得到两个不同的值呢?salt
是实际bcrypt值的前22个字符。字段由$
分隔-2b
表示bcrypt,12
表示12轮,下一个字符串是为密码存储的实际结果值(salt+结果bcrypt哈希(。这个字符串的前22个字符是纯文本中的salt。
如果你给bcrypt一个salt,而不是让它生成salt,你可以看到这一点(最后一个字符必须是[.Oeu]
中的一个,以匹配某些bcrypt实现的预期位填充-否则passlib将抛出错误或警告-其他字符必须匹配[./A-Za-z0-9]
的regex字符类(:
>>> pwd_context.hash("test", salt="a"*21 + "e")
'$2b$12$aaaaaaaaaaaaaaaaaaaaaehsFuAEeaAnjmdgkAxYfzHEipCaNQ0ES'
^--------------------^
如果我们明确给出相同的散列,结果应该是相同的(这就是以后验证密码的方式(:
>>> pwd_context.hash("test", salt="a"*21 + "e")
'$2b$12$aaaaaaaaaaaaaaaaaaaaaehsFuAEeaAnjmdgkAxYfzHEipCaNQ0ES'
>>> pwd_context.hash("test", salt="a"*21 + "e")
'$2b$12$aaaaaaaaaaaaaaaaaaaaaehsFuAEeaAnjmdgkAxYfzHEipCaNQ0ES'
前面的散列也是如此:
>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^--------------------^
这是实际生成的salt,然后与test
一起使用以创建实际的hash:
>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^-----------------------------^
那么,当每个人都能清楚地看到这种盐时,我们为什么要使用它呢?这使得不可能只在哈希列表中扫描已知的哈希-由于列表中的test
的值与您将其与之进行比较的列表中的test
的值不同(因为盐不同(,因此您必须实际测试猜测的密码及其盐,并通过哈希算法运行它们。bcrypt
是明确设计的,目的是让这个过程需要时间,所以你要花更长的时间来破解密码,而不仅仅是扫描2亿个密码的列表并在数据库中搜索已知的哈希。
它还将确保具有相同密码的两个用户不会收到相同的密码哈希,因此您无法通过查找在多个用户之间重复的密码哈希来快速确定弱密码(或者尝试确定两个用户是否是同一个人,因为他们具有相同的密码(。
那么,当计算机变得更快时,你该怎么办呢?增加12
参数-rounds
-这增加了哈希算法的运行时间,希望在更长的时间内保持更安全(可以将rounds
参数改为passlib.hash
(。