【Python入门】27.常用内置模块之 hashlib和hmac & 实现密码的加密储存

摘要::hashlib模块中包含常见的摘要(哈希)算法,如MD5,SHA1等;采用MD5加盐算法实现用户登录的验证;hmac是一种更为方便的加密算法。


写在前面:为了更好的学习python,博主记录下自己的学习路程。本学习笔记基于廖雪峰的Python教程,如有侵权,请告知删除。欢迎与博主一起学习Pythonヽ( ̄▽ ̄)ノ


目录

  • 常用内置模块
  • hashlib
    • MD5算法
    • SHA1算法
    • 摘要算法应用
    • 加盐salt
      • • 【练习】MD5加盐算法实现用户登录的验证
    • hmac

常用内置模块

hashlib

Python的hashlib模块提供了常见的摘要算法。

摘要算法,又称哈希算法(hash算法)。它通过一个摘要函数f( )把任意长度的数据date转化为一个固定长度的摘要digest

摘要算法不能用来加密,因为它可以简单地转化一个数据,但却很难进行反转化。可以说摘要算法是单向的,而且更改数据其中的一个bit都会让转化结果完全不一样。

常见的摘要算法有MD5SHA1等。

MD5算法

MD5是最常见的摘要算法,生成固定的128bit字节,通常用一个32位的16进制字符串表示。

下面看一下具体怎么使用摘要算法:

import hashlib                                # 引入hashlib模块
md5 = hashlib.md5('aaa'.encode('utf-8'))      # 调用hashlib的md5,输入参数aaa,并把aaa按utf-8编码bytes
print(md5.hexdigest())                        # 调用md5的hexdigest方法进行转化,并打印

运行结果:

47bce5c74f589f4867dbd57e9ca9f808 

需要注意的是,传入的数据文本要先转成bytes类型,才能进一步进行转化。

如果数据文本太长,可以通过update( )来分开输入:

import hashlib 

md5 = hashlib.md5()
md5.update('how to use hashlib'.encode('utf-8'))
md5.update('in python'.encode('utf-8'))

print(md5.hexdigest())

SHA1算法

SHA1算法生成固定的160bit,通常用一个40位的16进制字符串表示。SHA1比MD5更安全,但生成速度也就更慢,其用法与MD5一样,改为调用SHA1即可:

import hashlib 
sha1 = hashlib.sha1('aaa'.encode('utf-8')).hexdigest()
print(sha1)

运行结果:

7e240de74fb1ed08fa08d38063f6a6a91462a815 

摘要算法应用

既然不能用摘要算法加密文档,那有什么用呢?

摘要算法主要应用于储存用户登录的用户名与密码。

任何允许用户登录的网站都会把用户的用户名与密码储存到数据库中,如果以明文储存,一旦数据库泄露则会泄露用户的隐私,而且网站运维人员本身也不应该知道用户的密码。

所以,一般而言,都是储存用户密码的摘要,即通过摘要算法处理之后再储存。

当用户登录时,输入的密码先通过摘要算法转化,如果与之前储存的密码摘要一致,则通过验证。

加盐salt

采用摘要算法储存密码就一定安全了吗?其实不然。一些黑客先储存一些常用的简单密码的摘要,一旦匹配到,就能反推回去,像123这种密码:

密码 对应MD5值
123 202cb962ac59075b964b07152d234b70
123456 e10adc3949ba59abbe56e057f20f883e

或许你已经想到了,要解决这个问题,只要对原始的密码加一个复杂的字符串,再进行转化即可,这个过程俗称“加盐”

我们可以用用户特定的数据资料作为盐Salt,比如登录名(假设登录名不可修改)等。

• 【练习】MD5加盐算法实现用户登录的验证

根据用户输入的登录名和口令模拟用户注册,计算更安全的MD5,并验证用户的登录信息(该练习源自廖雪峰的官网)

# -*- coding:utf-8 -*-
import hashlib, random

# 计算MD5值的函数
def get_md5(s):                       
    return hashlib.md5(s.encode('utf_8')).hexdigest()

# 定义User类,储存用户信息
class User(object):
    def __init__(self, username, password):
        self.username = username
        # 通过random模块是实现salt的随机性
        self.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 login(username, password):
    user = db[username]
    return user.password == get_md5(password + user.salt)

# 测试:
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')

hmac

hmac算法,Keyed-Hashing for Message Authentication,也是一种加密算法。

hmac算法和上面介绍的加盐算法很相似,它通过一个标准算法,在计算hash值的过程中混入key

这里的“混入”并不是想salt那样简单的拼接。

hmac算法用起来方便很多,通过hmac.new,然后依次输入参数:随机key,原始信息message,哈希算法如MD5即可:

import hmac
message = b'how to use hmac'
key = b'key'
h = hmac.new(key, message, digestmod='MD5')
print(h.hexdigest())

运行结果:

fc81ce5e1a45ce8383aa1caf2f9b8dc0 

需要注意的是,这里的messagekey都要以bytes类型输入。

如果把上面用户注册并验证登录信息的例子改一下,用hmac算法实现,就变成这样:

# -*- coding: utf-8 -*-
import hmac, random

# 定义hmac算法函数
def hmac_md5(key, s):
    return hmac.new(key.encode('utf-8'), s.encode('utf-8'), 'MD5').hexdigest()

# 定义用户信息User类
class User(object):
    def __init__(self, username, password):
        self.username = username
        # 这里的salt变成key
        self.key = ''.join([chr(random.randint(48, 122)) for i in range(20)])
        self.password = hmac_md5(self.key, password)

# 输入用户信息
db = {
    'michael': User('michael', '123456'),
    'bob': User('bob', 'abc999'),
    'alice': User('alice', 'alice2008')
}

# 登录信息验证
def login(username, password):
    user = db[username]
    return user.password == hmac_md5(user.key, 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')

以上就是本节的全部内容,感谢你的阅读。

下一节内容:常用内置模块之 Itertools

有任何问题与想法,欢迎评论与吐槽。

和博主一起学习Python吧( ̄▽ ̄)~*

你可能感兴趣的:(Python入门,学习笔记,hashlib,哈希算法,MD5,hmac,加盐)