hashlib模块
hashlib模块是一个内部有摘要算法的模块,而且内部可以给我们提供不止一种摘要算法。
为什么需要摘要算法?
由于数据的不安全性,为了保证用户的信息的绝对安全,所有敏感的数据都不应该用明文传输,而应该经过适当的处理,通过密文来存储。摘要算法就是通过对任意长度的内容经过计算,转换为一个定长的16进制的字符串,目的是保证该文件没有被篡改过。摘要算法,之所以能够做到这点,是因为算法都是不可逆的。
为什么需要hashlib?
1.因为不同的字符串通过摘要算法得到的密码总是不同的,相同的算法相同的字符串总是相同的。
2.在不同的编程语言,不同的环境(操作系统,版本,时间),都是一致的,不存在差异。
hashlib模块的使用
hashlib模块提供了多种摘要算法:
md5算法: 定长32位 16进制(应用最广发的摘要算法)
sha系统算法: 定长40位
#sha算法要比MD5算法更加复杂,且sha N数值越大,算法越复杂,耗时越久,结果越长,但也更安全
#hashlib模块md5摘要算法的使用 name = 'alex' password = 'alex3714' #1.首先,需要先实例化一个md5的对象,一个对象只加密一个数据 md5_obj = hashlib.md5() #2. update()方法,把需要进行MD5的对象放入 md5_obj.update(password.encode('utf-8')) #3.通过hexdigest(),得到摘要算法之后的密文 md5_password = md5_obj.hexdigest() print(md5_password) print(len(md5_password)) #md5算法,定长32位 >>> aee949757a2e698417463d47acac93df 32
# 使用sha摘要算法
name = 'alex'
password = 'alex3714'
#操作与md5如出一辙,先创建对象,通过update加密,在通过hexdigest取值
sha_obj = hashlib.sha1()
sha_obj.update(password.encode('utf-8'))
sha_password = sha_obj.hexdigest()
print(sha_password)
print(len(sha_password)) #sha1算法定长40位
>>>
8a003668a9c990f15148f9e4046e1410781533b6
40
hashlib的应用
- 用户登录的验证
name | password --------+---------- hehehe | hehehe1994
有一个用户hehehe,密码为hehehe1994,如果密码就这样用明文存储,如果数据库被黑客侵入,那么密码就毫无保留的暴露给了黑客。所以这时候就需要用到摘要,在数据库中,存储密码的摘要信息。每次登陆的时候,在做摘要信息的比对。
username | password ---------+--------------------------------- michael |69d5dd8a4651f8c77adc140c53469479
所以每次登陆的时候,便需要进行密码信息的摘要比对。
def get_md5_pws(s): md5_obj = hashlib.md5() md5_obj.update(s.encode('utf-8')) ret = md5_obj.hexdigest() return ret username = input('username>>>:').strip() password = input('password>>>:').strip() with open('userinfo',encoding='utf-8') as f: for line in f: usr,pwd = line.strip().split('|') if username == usr and get_md5_pws(password) == pwd: print('登录成功') break else: print('登录失败')
通过摘要算法的手段,虽然密码是用密文的形式存储了,但是在现在的攻击手段中,有一种叫做"撞库"的手段,就是通过一个存储着大量密码与md5后的摘要对应的关系,再一一进行匹配,如果摘要信息一致,便能够反推出密码,因为同一种算法的同一个字符串,结果总是不变的。那么,有什么方法能够防止撞库?那就通过加盐值得手段(1.固定盐值 2.更好的方法:动态加盐)
何为盐值(salt),其实就是给原数据+一段指定的字符串,这样得到的MD5值就会发生变化。只要颜值不被黑客知道,那么就很难反向推出原数据。
#加盐的md5算法,采用固定盐值(盐值:salt) username = 'hehehe' password = 'hehehe1994' md5_obj = hashlib.md5('salt'.encode('utf-8')) #加盐 md5_obj.update('alex3714'.encode('utf-8')) ret = md5_obj.hexdigest() print(ret) #动态加盐,通过把用户的唯一标识作为盐值,例如每个用户的用户名都是唯一 username = 'hehehe' password = 'hehehe1994' md5_obj = hashlib.md5(username.encode('utf-8')) #动态加盐 md5_obj.update('alex3714'.encode('utf-8')) ret = md5_obj.hexdigest() print(ret)
- 文件一致性的校验
给一个文件中的所有内容进行摘要算法,得到一个md5结果。此时,我们可以体验到md5摘要算法的神奇的地方,对于同一个字符串,不管把他拆开多少段,最终得到的md5值都是一样。
# 同一个字符串,不管拆开多少段,最终的md5都是一样的。 slogan= 'hello,python' md5_obj1 = hashlib.md5() md5_obj1.update(slogan.encode('utf-8')) ret1 = md5_obj1.hexdigest() print(ret1) >>> 15ac32041ff74c93c1842b152df7519e md5_obj2 = hashlib.md5() md5_obj2.update('hello,'.encode('utf-8')) md5_obj2.update('python'.encode('utf-8')) ret2 = md5_obj2.hexdigest() print(ret2) >>> 15ac32041ff74c93c1842b152df7519e
所以,对文件进行一致性校验。
def get_file_md5(file_path): md5_obj = hashlib.md5() with open(file_path,encoding='utf-8') as f: for line in f: md5_obj.update(line.encode('utf-8')) ret = md5_obj.hexdigest() return ret
- 对视频进行一致性校验
一般是视频格式的文件/网络传输的文件,都是二进制的bytes类型。此时没有行的概念,该怎么做?此时,可以设置一个buffer,每次都读取相同长度的buffer.
#设置一个buffer,每次都通过f.read(buffer)读取定长的数据。
def get_video_md5(file_path,buffer=1024):
file_size = os.path.getsize(file_path)
md5_obj = hashlib.md5()
with open(file_path, 'rb') as f:
while file_size:
content = f.read(buffer)
file_size-= len(content)
md5_obj.update(content)
return md5_obj.hexdigest()