Fork me on GitHub

python生成hash值

Hash(哈希),又称散列,是把任意长度的输入(又称预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。

而python的hashlib模块是个专门提供hash算法的库,由python自带,支持openssl库提供的所有算法,包括md5, sha1, sha224, sha256, sha384, sha512。
具体可以使用hashlib.algorithms_available来查看当前支持的hash算法列表。
值得注意的是,哈希算法不可逆向,并不是加密,可以提取摘要,通常用于一些文件、登录密码的校验。
例如,一个用于储存用户登录数据的数据库,如果全以明文保存,如果数据库泄露,所有用户的密码就会泄露。不仅如此,只要有人能访问该数据库,也能获取到所有用户的密码。

那么使用哈希算法,只储存用户密码的摘要,当用户登录时,首先计算用户输入的明文密码的摘要,和数据库存储的数据进行对比,即可验证密码是否正确。

代码实现

MD5

1
2
import hashlib
print(hashlib.md5('12345'.encode()).hexdigest())

上面的代码即可输出字符串”12345”的MD5值。
计算结果为:

1
827ccb0eea8a706c4c34a16891f84e7b

计算字符串”123456”的MD5值为e10adc3949ba59abbe56e057f20f883e
我们可以看出,MD5值并无规律可循。只需改动一点点,MD5值就会变动很多。

sha1

实现也非常简单:

1
2
import hashlib
print(hashlib.sha1('12345'.encode()).hexdigest())

MD5算法已经是几年前的hash算法了,早已停止维护。而sha1比MD5生成的结果要更长,因此也更安全。

sha224,sha256,sha384,sha512

1
2
3
4
5
6
import hashlib

print(hashlib.sha224('12345'.encode()).hexdigest())
print(hashlib.sha256('12345'.encode()).hexdigest())
print(hashlib.sha384('12345'.encode()).hexdigest())
print(hashlib.sha512('12345'.encode()).hexdigest())

值得注意的是,随着哈希算法版本的升高,会越来越安全,但是越安全的算法不仅越慢,而且摘要长度更长。

那么,有没有可能两个不同的数据通过某个摘要算法得到了相同的摘要?其实完全是有可能的,毕竟任何摘要算法都是把无限多的数据集合映射到一个有限的集合中。这种情况称为碰撞,也并非不可能出现,但是几率非常的小。
那么采用摘要存储密码是否就一定安全呢?事实上也不一定,如果已经得到了一个MD5值,能否反推得到原字符串?暴力破解过于耗时。很多用户喜欢用123456,abcdef,loveyou,qwer,!@#等简单的密码,黑客可以事先通过摘要算法计算出这些常用密码的摘要值,得到一个反推表(例如sha1),然后即可得到原字符串:

1
2
3
4
5
7c4a8d09ca3762af61e59520943dc26494f8941b : 123456
1f8ac10f23c5b5bc1167bda84b833e5c057a77d2 : abcdef
f4cc6e82140048ead7015f2917eb56e3e50a1f00 : loveyou
1161e6ffd3637b302a5cd74076283a7bd1fc20d3 : qwer
....

那么,我们还可以使用加盐(salt)来使其更安全。
加盐:额外给原始数据添加一点自定义的数据,使得生成的消息摘要不同于普通方式计算的摘要。
例如下面的代码,添加了”aabcc”作为盐:

1
2
3
4
import hashlib
salt='aabcc'
password='12345'+salt
print(hashlib.sha1(password.encode()).hexdigest())

经过加盐处理的密码,只要自定义的“salt”不被黑客知道,即使用户使用的是非常简单的密码,也很难反推出明文密码。
这样便可保证登录数据的安全。