Python密码哈希法
我们将学习密码散列,以及如何用一个名为bcrypt
的第三方库加密盐和散列密码。我们还看看Python中hashlib
库的不同散列算法。
使用Python中的bcrypt
库对密码进行加盐和哈希处理
散列是将一个字符串变成一个固定长度的看似随机的字符串的过程,这个过程是不可逆的。它是一个单向函数,所以你不能像加密那样将哈希值返回到它的原始字符串,你可以对一个信息进行加密,然后再解密。
散列用于用户管理;例如,如果我们有一些数据库漏洞或丢失数据,或者当我们使用明文密码时有人黑进我们的系统。散列给了我们一些保护层;然而,如果我们适当地维护它,散列的密码不容易被破解。
在本节中,我们将看到如何使用bcrypt
模块来处理散列的密码;让我们继续前进,跳入代码。我们将使用一个名为bcrypt
的第三方库,它是一种散列算法。
bcrypt
是一种可靠的、稳健的、被推荐用于散列密码的算法;它给我们提供了一些不错的、简单易用的功能,让我们快速完成工作。
首先,我们将使用以下命令来安装这个库。
pip install bcrypt
现在我们需要导入bcrypt
,创建一个密码,并将其存储在一个变量中,而且这个密码必须是一个字节字符串。为了哈希这个密码,我们将创建一个名为hashed_pswd
的新变量,并调用bcrypt
的hashpw()
方法。
它需要两个参数;第一个是密码,第二个是叫做gensalt()
的东西,随机生成一个数字或一个盐和哈希密码。
import bcrypt
My_pswd = b"Mypassword111"
hashed_pswd = bcrypt.hashpw(My_pswd, bcrypt.gensalt())
print(hashed_pswd)
输出:
b'$2b$12$KEW01pYNDc3ee9U0wZpmgOBpUvvjkig/qxs593hGh/aZ2AvvGTyWu'
使用hashlib
库哈希一个密码
本节将使用hashlib
库来创建一个盐和散列密码。如果你把安全数据如密码之类的东西从一个地方传到另一个地方,最好能确保有人无法读取这些数据。
当你想隐藏一些东西或让用户无法阅读时,有两种类型的事情可以做。第一种是散列法,第二种是加密法;加密法大多不用于密码。
如果我们想把文件从我们的计算机转移到另一台计算机上,或者发送一个文件,那么我们就使用加密。但是,如果我们想检查密码是否正确,或者在我们的服务器中存储密码,那么大多使用散列。
hashlib
库最好的一点是,我们不需要安装任何东西;它是Python 3或更高版本的。在导入hashlib
之后,我们将创建一个名为MD5_Algo
的对象,并从hashlib
中调用md5()
。
md5
是一种散列算法, 代表 ,而 是版本。现在我们需要将明文转换为散列的字符串,为此,我们调用 方法,并写入我们要散列的字符串。md
message-digest
5
update()
然后在print()
函数里面,我们调用hexdigest()
方法;在将应变转换为实际的md5
,它转换为十六进制形式。
import hashlib
MD5_Algo=hashlib.md5()
MD5_Algo.update('hello')
print(MD5_Algo.hexdigest())
这段代码会抛出一个错误(Unicode对象必须在散列前进行编码),在上一节中,我们已经讨论过,我们需要将字符串转换成字节。
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~AppDataLocalTemp/ipykernel_4064/2416014515.py in <module>
2
3 MD5_Algo=hashlib.md5()
----> 4 MD5_Algo.update('hello')
5 print(MD5_Algo.hexdigest())
TypeError: Unicode-objects must be encoded before hashing
将字符串转换为字节后,我们看到它给了我们一个md5
加密的散列密码。
import hashlib
MD5_Algo=hashlib.md5()
MD5_Algo.update(b'hello')
print(MD5_Algo.hexdigest())
输出:
5d41402abc4b2a76b9719d911017c592
hashlib.sha512()
还有其他种类的加密散列;让我们看看Python里面到底有什么样的散列东西。我们可以使用algorithms_available
属性打印出可用的算法。
print(hashlib.algorithms_available)
输出:
{'md4', 'md5', 'shake_256', 'shake_128', 'sha512_224', 'md5-sha1', 'sha224', 'sha3_512', 'sha1', 'sha3_384', 'sha512', 'sha3_224', 'sha512_256', 'sha384', 'sha256', 'blake2b', 'sha3_256', 'blake2s', 'ripemd160', 'whirlpool', 'sm3', 'mdc2'}
正如我们所看到的,有很多很酷的算法,显然,所有这些对象都有相同的结构,它们会有相同的函数和变量,但只是算法不同而已。
sha512
是我们将使用的,并传入一个字符串;之后,我们对该字符串使用 ,该字符串将被散列。hexdigest()
import hashlib
MD5_Algo=hashlib.sha512(b'hello')
print(MD5_Algo.hexdigest())
当我们运行这段代码时,我们会得到一长串的字符。
9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
sha512
是比 更强和更好的一种;这完全取决于你在你的情况下确定的更好或最好的方案。sha1
盐化和哈希
这类旧算法的问题是,它们可以被破解或反向工程,而且它并不那么安全,因为每个人都可以轻易地解密这个加密的哈希值。我们的加密哈希值是hello
;如果我们做一个字典攻击,从sha512
字典中解密呢?
sha512
的缺点是,许多人在 Facebook 或其他应用程序上使用他们的密码;通常,他们使用他们的生日,而这些生日已经在sha512
中被反过来看了,所以这就是为什么这不是一个安全的方式。
最安全的方法之一是加盐;加盐会在你的原始字符串前面添加一些字符。比方说,如果我们在"hello"
前面加上"a"
,我们就在原始字符串前面加上了字符"a"
作为盐。
hashlib.sha512(b'helloa')
现在我们已经用这个额外的盐对这个哈希值进行了加密,这就是为什么黑客和其他试图解密这个哈希值的人将会非常困难,所以这就是盐的作用。
hashlib.pbkdf2_hmac()
在Python中,hashlib
库有一个函数,虽然有点慢,但却是一个相当好的函数,叫做pbkdf2_hmac()
。我们将使用这个函数,第二个库实际上是用于将二进制转换为ASCII字符。
pbkdf2_hmac()
需要几个参数;第一个参数是我们将使用的算法的名称,所以我们在这个例子中使用sha512
。下一个是密码或我们要哈希的文本;在这种情况下,它将是"hello"
。
下一个被称为盐,盐将被添加到这个密码中,然后它们将使用sha512
进行加密。最后一个是迭代次数;如果我们做这个迭代十万次,那么要找到它来解密就非常困难了。
在最后一行代码中,我们使用binascii
库中的hexlify()
方法将加密后的哈希值转换为ASCII字符。
import hashlib, binascii
Enc_Salt = hashlib.pbkdf2_hmac('sha512',b'hello',b'a',100000)
print(binascii.hexlify(Enc_Salt))
输出:
b'40b5957a2d2f5aebcdd878a04e644215d4f3aba3f11c00a1f24e75f8ea2efa11611b2a923a9050832cb768a3a3ad282011cab524b741d392c664b8efbb5f389f'
现在我们可以看到sha512
字典无法解密。