hashlib模块
【一】什么是摘要算法
- Python的hashlib提供了常见的摘要算法
- 摘要算法又称哈希算法、散列算法。
- 它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
- 摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest
- 摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数
- 计算f(data)很容易,但通过digest反推data却非常困难。
- 而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
【二】摘要算法(md5)
【1】加密数据
(1)一次性加密(同一段数据)
- 以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
| import hashlib |
| |
| md5 = hashlib.md5() |
| |
| a = 'heart' |
| a = a.encode('utf8') |
| md5.update(a) |
| print(md5.hexdigest()) |
(2)分次加密(同一段数据)
- 如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的
- MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。
| import hashlib |
| |
| md5 = hashlib.md5() |
| |
| a = 'hello' |
| b = 'heart' |
| a = a.encode('utf8') |
| b = b.encode('utf8') |
| md5.update(a) |
| md5.update(b) |
| print(md5.hexdigest()) |
【2】获取加密数据
| from hashlib import md5 |
| |
| |
| data = '哈特' |
| md5_obj = md5() |
| data = data.encode('utf-8') |
| md5_obj.update(data) |
| |
| print(md5_obj.digest()) |
| |
| print(md5_obj.hexdigest()) |
【三】摘要算法升级之加盐
- 任何允许用户登录的网站都会存储用户登录的用户名和口令。
- 如何存储用户名和口令呢?
| name | password |
| |
| michael | 123456 |
| bob | abc999 |
| alice | alice2008 |
- 如果以明文保存用户口令,如果数据库泄露,所有用户的口令就落入黑客的手里。
- 此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的口令。
- 正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,比如MD5:
| username | password |
| |
| michael | e10adc3949ba59abbe56e057f20f883e |
| bob | 878ef96e86145580c38c87f0410ad153 |
| alice | 99b1c2188db85afee403b1536010c2c9 |
- 考虑这么个情况,很多用户喜欢用123456,888888,password这些简单的口令
- 于是,黑客可以事先计算出这些常用口令的MD5值,得到一个反推表:
| 'e10adc3949ba59abbe56e057f20f883e': '123456' |
| '21218cca77804d2ba1922c33e0151105': '888888' |
| '5f4dcc3b5aa765d61d8327deb882cf99': 'password' |
- 这样,无需破解,只需要对比数据库的MD5,黑客就获得了使用常用口令的用户账号。
- 对于用户来讲,当然不要使用过于简单的口令。
- 由于常用口令的MD5值很容易被计算出来
- 所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5
- 这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:
| hashlib.md5("salt".encode("utf8")) |
- 经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。
- 但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。
- 有没有办法让使用相同口令的用户存储不同的MD5呢?
- 如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。
- 摘要算法在很多地方都有广泛的应用。
- 要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
摘要算法加密的特点是 : 相同的数据加密出来的加密串是一样的,不同的数据的加密串肯定是不一样的
每个网站都会有一个数据库 : 数据库里面存了这些密码的加密串
破解方法:撞库
防止撞库的破解方法 --->>加盐
| md5_one = hashlib.md5() |
| |
| data = '123456' |
| |
| |
| data = data.encode('utf8') |
| salt = '888' |
| salt = salt.encode('utf8') |
| md5_one.update(data) |
| md5_one.update(salt) |
| |
| print(md5_one.hexdigest()) |
【四】摘要算法模版
| import hashlib |
| |
| def get_md5_digest(salt,data): |
| data = salt + data |
| b_data = data.encode('utf-8') |
| encrypted_data = hashlib.md5(b_data) |
| |
| return encrypted_data.hexdigest() |
【五】注册登录里加密加盐
| import random |
| import hashlib |
| import json |
| def get_verify_code(n): |
| code = '' |
| for i in range(n): |
| random_int = str(random.randint(0, 9)) |
| random_upper = chr(random.randint(65, 90)) |
| random_lower = chr(random.randint(97, 122)) |
| temp = random.choice([random_int, random_upper, random_lower]) |
| code += temp |
| return code |
| |
| def create_has(data,salt): |
| data = str(data) +str(salt) |
| data = data.encode('utf8') |
| data1=hashlib.md5() |
| data1.update(data) |
| aa = data1.hexdigest() |
| return aa |
| |
| def save_data(data): |
| with open('user_pwd.json','a',encoding='utf-8')as f: |
| json.dump(data,f,ensure_ascii=False) |
| |
| def register(): |
| username =input('请输入用户名:>>>').strip() |
| password = input('请输入密码:>>>').strip() |
| |
| yzm = get_verify_code(6) |
| yanzhengma = input(f'请输入六位验证码 {yzm}:>>>').strip() |
| if yzm.upper() != yanzhengma.upper(): |
| print('验证码错误!') |
| |
| salt = get_verify_code(4) |
| password = create_has(data=password,salt=salt) |
| user_data = {username:{'username':username,'password':password,'salt':salt}} |
| save_data(data=user_data) |
| print(user_data) |
| |
| |
| |
| def read_data(): |
| with open('user_pwd.json','r',encoding='utf-8')as f: |
| data = json.load(f) |
| return data |
| |
| def login(): |
| username =input('请输入用户名:>>>').strip() |
| password = input('请输入密码:>>>').strip() |
| data =read_data() |
| user_data = data.get(username) |
| salt = user_data.get('salt') |
| password = create_has(data=password,salt=salt) |
| if password == user_data.get('password'): |
| print('登陆成功!') |
| else: |
| print('密码不对!') |
| |
| login() |
time模块
| 【需要记住的】 |
| 时间戳 :time.time() |
| 时间元组 : time.localtime() |
| 格式化输出时间 : time.strftime(format,时间元组) |
| 指定日期和时间转换为时间元组 : time.strptime(自定义时间,时间格式) |
【一】时间戳time.time()
time.time()
是time模块中的一个函数,用于获取当前时间戳,返回自纪元(Epoch)以来的秒数,通常是一个浮点数。
- 这个函数在很多情况下都很有用,例如在性能测试、计时等需要测量时间的场景中。请注意,由于时间戳是以秒为单位的浮点数,可以通过差值计算时间间隔,或者转换为日期时间格式以便更容易阅读。
| import time |
| |
| current_time = time.time() |
| print("当前时间戳:", current_time) |
【二】时间元组time.localtime()
time.localtime()
是 time 模块中的一个函数,用于将一个时间戳(秒数)转换为本地时间的结构化表示。它返回一个包含年、月、日等时间信息的元组。
- 以下是
time.localtime()
的简要介绍:
| import time |
| |
| current_time = time.time() |
| local_time = time.localtime(current_time) |
| |
| print("当前时间戳:", current_time) |
| print("本地时间结构:", local_time) |
| |
-
time.strftime(format, 时间元组)
是time模块中的一个函数,用于将时间元组格式化为字符串。它接受两个参数:format
是格式化字符串,用于定义输出的时间格式,而 时间元组
是包含时间信息的元组对象。
-
以下是 time.strftime()
的简要介绍:
| import time |
| |
| |
| local_time_tuple = time.localtime() |
| |
| |
| formatted_time = time.strftime("%Y-%m-%d %X", local_time_tuple) |
| |
| print("本地时间元组:", local_time_tuple) |
| |
| print("格式化时间字符串:", formatted_time) |
| |
【四】指定日期和时间转换为时间元组time.strptime(自定义时间,时间格式)
-
time.strptime(自定义时间, 时间格式)
是 time模块中的一个函数,用于将指定格式的日期和时间字符串解析为时间元组。这个函数的作用是与 time.strftime()
相反,后者是将时间元组格式化为字符串,而 time.strptime()
是将字符串解析为时间元组。
-
以下是 time.strptime()
的简要介绍:
| import time |
| |
| |
| time_tuple = time.strptime("2023-01-01 12:30:45","%Y-%m-%d %X") |
| |
| print("解析后的时间元组:", time_tuple) |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通