常用模块-随机和哈希

1 random 模块

该模块用于生成随机数

1.1 取随机数

import random

print(random.random())                    #(0,1)----float    大于0且小于1之间的小数
print(random.randint(1,3))              #[1,3]    大于等于1且小于等于3之间的整数
print(random.randrange(1,3))             #[1,3)    大于等于1且小于3之间的整数
print(random.choice([1,'23',[4,5]]))    #1或者23或者[4,5]
print(random.sample([1,'23',[4,5]],2))    #列表元素任意2个组合 返回列表
print(random.uniform(1,3))                #大于等于1小于3的小数,如1.927109612082716

1.2 打乱列表 shuffle

import random
item=[1,3,5,7,9]
random.shuffle(item)     #打乱item的顺序,相当于"洗牌"
print(item)

1.3 练习

生成随机验证码 随机字母和数字

import random
def make_code(n):
    res=''
    for i in range(n):
        s1=chr(random.randint(65,90))
        s2=str(random.randint(0,9))
        res+=random.choice([s1,s2])
    return res

print(make_code(9))

2 hashlib 模块

Python的hashlib提供了常见的哈希算法,如MD5,SHA1等等

2.1 什么是哈希(hash)

哈希算法又称摘要算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)

每个字符串都已通过哈希算法生成固定且唯一的哈希值,字符串发生改变,对应的哈希值也会改变

哈希值的特点如下

  1. 只要传入的内容一样,得到的hash值必然一样
  2. 不能由hash值返解成内容,hash运算时单向的,不可逆
  3. 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的

2.2 hashlib模块中的哈希算法

hashlib模块主要提供了如下哈希方法

  • md5 32位16进制数 128位2进制数
  • sha1 40位16进制数 160位2进制数
  • sha224 56位16进制数 224位2进制数
  • sha256 64位16进制数 256位2进制数
  • sha384 96位16进制数 384位2进制数
  • sha512 128位16进制数 512位2进制数

2.3 hashlib的使用

import hashlib

md5 = hashlib.md5('123456'.encode('utf-8'))
print(md5.hexdigest())
import hashlib

md5 = hashlib.md5()
md5.update('hello dandan'.encode('utf-8'))
print(md5.hexdigest())  # 32087773681bb6ada67d151105d37e70

sha1 = hashlib.sha1()
sha1.update('hello dandan'.encode('utf-8'))
print(sha1.hexdigest())     # 31b1b4c4f4775f181aba04695dfabd502513d931

sha224 = hashlib.sha224()
sha224.update('hello dandan'.encode('utf-8'))
print(sha224.hexdigest())   #067e2173f2395ef76a069eccdf4279a19d0fb9fe078b722ad99afed7

sha256 = hashlib.sha256()
sha256.update('hello dandan'.encode('utf-8'))
print(sha256.hexdigest())   # a6c38c125bc355cd82ee59066b4f20c495f629d6cd61cfd1619dc5e2df18bc00

sha384 = hashlib.sha384()
sha384.update('hello dandan'.encode('utf-8'))
print(sha384.hexdigest())   # b88b7dfee7274331cd1cea7a74906979282e68c0e5a71cd2cd1515b0a0962440747cce6421e1a3e8a7b720dbb4a3dd60

sha512 = hashlib.sha512()
sha512.update('hello dandan'.encode('utf-8'))
print(sha512.hexdigest())   # 48c5392ea75b8270fff69a19ac7e6a47b12e88135967b7db1356e6bf5bd8ac21edb40b5ba933ce8f7cf5038d29f9b1a743bce9f896a236f4835d1f31c6ae4d0f

注意

调用多次update()方法,实际上实在拼接字符串,如果需要加密的内容比较长,可以调用多次 update()

2.4 提高加密安全性

以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。

import hashlib

# ######## 256 ########

hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
hash.update('alvin'.encode('utf8'))
print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7

以下模拟md5解密

import hashlib

md5 = hashlib.md5()
md5.update('123456'.encode('utf-8'))
print(md5.hexdigest())

passwds=[
    'dan3714',
    'dan1313',
    'dan94139413',
    'dan123456',
    '123456dan',
    'a123l',
    '123456'
    ]
def make_passwd_dic(passwds):
    dic={}
    for passwd in passwds:
        m=hashlib.md5()
        m.update(passwd.encode('utf-8'))
        dic[passwd]=m.hexdigest()
    return dic

def break_code(cryptograph,passwd_dic):
    for k,v in passwd_dic.items():
        if v == cryptograph:
            print('密码是 : \033[46m%s\033[0m' %k)

cryptograph = 'e10adc3949ba59abbe56e057f20f883e'
break_code(cryptograph, make_passwd_dic(passwds))

3 hmac 模块

前面提到为了加密更安全,我们再加密内容中,混入了Key, 实际上真正进行哈希运算的是 我设置的key+要加密的内容, 这实际上就是Hmac算法 (Keyed-Hashing for Message Authentication)

hmac模块实现了标准的Hmac算法,采用Hmac替代我们自己生成Key,可以使程序算法更标准化,也更安全。

import hmac
message = b'Hello, world!'
key = b'secret'
h = hmac.new(key, message, digestmod='MD5')  #digestmod 默认值是 MD5
# 如果消息很长,可以多次调用h.update(msg)
h.hexdigest()  'fa4ee7d173f2d97ee79022d1a7355bcf'
import hmac

h1=hmac.new(b'dandan')
h1.update(b'hello')
h1.update(b'world')
print(h1.hexdigest())

h2=hmac.new(b'dandan')
h2.update(b'helloworld')
print(h2.hexdigest())

h3=hmac.new(b'dandan', b'helloworld')
print(h3.hexdigest())

4 哈希应用

4.1 存储密码

用户密码经过 哈希运算 后,将哈希值也就是密文 存入数据库

当验证的时候, 将用户输入的明文,计算哈希值,用哈希值与存储在数据库的密文进行比较

如此,即使数据库泄露也会将密码的明文泄露,此外,运维人员和数据库管理人员也无法读取到用户的密码明文

4.2 哈希碰撞

如果不同的输入得到了同一个哈希值,就发生了"哈希碰撞"(collision)

防止哈希碰撞的最有效方法,就是扩大哈希值的取值空间。

16个二进制位的哈希值,产生碰撞的可能性是 65536 分之一。也就是说,如果有65537个用户,就一定会产生碰撞。哈希值的长度扩大到32个二进制位,碰撞的可能性就会下降到 4,294,967,296 分之一。

更长的哈希值意味着更大的存储空间、更多的计算,将影响性能和成本。开发者必须做出抉择,在安全与成本之间找到平衡。

results matching ""

    No results matching ""