Python常用内建模块——hashlib
哈希早在大一下学python课程就有所领略,当时被动的接收让我觉得挺难的。但今天静下来学了廖老师的课程之后发现并不难,甚至可以说非常公式化。
首先,hashlib
模块实现了多种安全哈希算法的通用接口,包括 MD5、SHA 系列(SHA1、SHA224、SHA256、SHA384、SHA512)、SHA3 系列以及 BLAKE2,而我们常用的一般就是MD5,以及SHA1。
其主要特点包括:
1.算法统一接口:所有哈希算法对象都共享相同的方法(如 update()
, digest()
, hexdigest()
),调用方式标准化。
2.不可逆性:哈希值无法还原出原始数据,常用于加密验证。
3.确定性:相同输入总是产生相同的哈希值。
4.内存优化:支持分块处理大文件,避免内存溢出。
我们以常见的哈希算法MD5为例,计算出一个字符串的MD5值:
另一种常见的哈希算法是SHA1,调用SHA1和调用MD5完全类似:
哈希算法在用户密码的安全性上有着广泛的应用:
任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中:
name | password |
---|---|
michael | 123456 |
bob | abc999 |
alice | alice2008 |
如果以明文保存用户口令,如果数据库泄露,所有用户的口令就落入黑客的手里。此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的口令。
正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的哈希,比如MD5:
username | password |
---|---|
michael | e10adc3949ba59abbe56e057f20f883e |
bob | 878ef96e86145580c38c87f0410ad153 |
alice | 99b1c2188db85afee403b1536010c2c9 |
当用户登录时,首先计算用户输入的明文口令的MD5,然后和数据库存储的MD5对比,如果一致,说明口令输入正确,如果不一致,口令肯定错误。
练习一
根据用户输入的口令,计算出存储在数据库中的MD5口令:
def calc_md5(password):pass
存储MD5的好处是即使运维人员能访问数据库,也无法获知用户的明文口令。
设计一个验证用户登录的函数,根据用户输入的口令是否正确,返回True或False:
db = {'michael': 'e10adc3949ba59abbe56e057f20f883e','bob': '878ef96e86145580c38c87f0410ad153','alice': '99b1c2188db85afee403b1536010c2c9'
}def login(user, password):pass# 测试:
assert login('michael', '123456')
assert login('bob', 'abc999')
assert login('alice', 'alice2008')
assert not login('michael', '1234567')
assert not login('bob', '123456')
assert not login('alice', 'Alice2008')
print('ok')
练习二
根据用户输入的登录名和口令模拟用户注册,计算更安全的MD5:
db = {}def register(username, password):db[username] = get_md5(password + username + 'the-Salt')
然后,根据修改后的MD5算法实现用户登录的验证:
import hashlib, randomclass User(object):def __init__(self, username, password):self.username = usernameself.salt = ''.join([chr(random.randint(48, 122)) for i in range(20)])self.password = get_md5(password + self.salt)db = {'michael': User('michael', '123456'),'bob': User('bob', 'abc999'),'alice': User('alice', 'alice2008')
}def get_md5(user, pws):return ???def login(username, password):user = db[username]return user.password == get_md5(user, password)# 测试:
assert login('michael', '123456')
assert login('bob', 'abc999')
assert login('alice', 'alice2008')
assert not login('michael', '1234567')
assert not login('bob', '123456')
assert not login('alice', 'Alice2008')
print('ok')
对于第二题的解释
实现功能:
1. 1.
用户注册系统 :使用固定salt ('the-Salt') 增强密码安全性
2. 2.
用户登录验证系统 :使用随机salt为每个用户生成独特的密码哈希
核心实现:
- get_md5(s) 函数:将输入字符串转换为字节串,计算并返回MD5哈希值的十六进制表示
- register(username, password) 函数:使用固定salt计算密码哈希并存储
- User 类:为每个用户生成随机salt并计算密码哈希
- login(username, password) 函数:验证用户凭据,使用对应用户的salt重新计算密码哈希并比较
安全特性:
- 使用随机salt为每个用户生成不同的密码哈希,即使相同密码也会产生不同的哈希值
- 结合用户名和salt进一步增强密码安全性
- 存储哈希值而非明文密码