天天看点

Python基础之hashlib模块和configparse模块

hashlib模块

Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

摘要算法

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

摘要算法意义

  • 摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
  • 摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

下面演示摘要算法之MD5算法:

import hashlib

md5_obj = hashlib.md5()
md5_obj.update("How to learn Python well?".encode('utf-8'))
print(md5_obj.hexdigest())
           

结果:

c0edd4e12a5b8c2ca894943c4b4d0116

Process finished with exit code 0

注意:在使用update()方法时,需要将待操作对象转为bytes类型。

MD5算法是最常见的摘要算法,速度很快,生成结果是固定的128字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:

import hashlib

sha1_obj = hashlib.sha1()
sha1_obj.update("How to learn Python well?".encode('utf-8'))
print(sha1_obj.hexdigest())
           

结果:

48f55ab58a5d6b64d84bd67c8df1d673afaeafec

Process finished with exit code 0

SHA1的结果是160字节、,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长。

这些算法中,字符串等信息固定,得到的值永远是确定且唯一的,用户不用担心信息出现问题。

摘要算法应用

任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中:

用户信息

name password
张三 zhangsan123456
李四 lisi987654321
王五 wangwu5201314

如果以明文保存用户口令,如果数据库泄露,所有用户的口令就落入黑客的手里。此外,网站管理员是可以访问数据库的,也就是能获取到所有用户的口令。正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,下面利用MD5算法加密后的用户信息:

由于算法得到的值是确定的,用户密码简单的时候是可能经过计算反推得到用户信息,某些黑客可能就会有一些特殊的反推表:

'e10adc3949ba59abbe56e057f20f883e'         '123456'

'21218cca77804d2ba1922c33e0151105'        '888888' '

5f4dcc3b5aa765d61d8327deb882cf99'          'password'

当窃取到数据时,便可以对照得出一些相关的信息,这样造成了很多的不安全。所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:

import hashlib

md5_obj1 = hashlib.md5()  # 不加盐
md5_obj1.update("张三".encode('utf-8'))
print(md5_obj1.hexdigest())

md5_obj2 = hashlib.md5("这是我加的盐".encode('utf-8'))  # 加盐
md5_obj2.update("张三".encode('utf-8'))
print(md5_obj2.hexdigest())
           

结果:

615db57aa314529aaa0fbe95b3e95bd3

0679a376a67c97aed8efd9b1f11d8bc8

Process finished with exit code 0

我们只要严格保守加的“盐”的数据,就不用担心出现加密信息被反推了。

但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?

如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。

这就是现在为什么注册用户名不能重名的原因:

import hashlib

username = input("Please input your username:")
password = input("Please input your password:")
md5_obj = hashlib.md5(username.encode('utf-8'))
md5_obj.update(password.encode('utf-8'))
print(md5_obj.hexdigest())
           

结果:

Please input your username:Python

Please input your password:123456

45267c5b6c1b421832d62d44f97a6915

Process finished with exit code 0

configparser模块

该模块适用于配置文件的格式为*.ini的文件,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。

*.ini,*.inc之类的文件是初始配置文件,程序在关闭时将全部配置都保存到INI中,下次打开时就会跟据INI里的参数来初始化应用程序的配置。

创建文件

一般情况我们看见的很多软件的常见*.ini文档格式如下:

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
  
[bitbucket.org]
User = hg
  
[topsecret.server.com]
Port = 50022
ForwardX11 = no
           

如果我们想要用Python生成这样一个文件,我们应该怎么做呢?

import configparser

config = configparser.ConfigParser()
config['DEFAULT'] = {'ServerAliveInterval': '45',
                     'Compression': 'yes',
                     'CompressionLevel': '9',
                     'ForwardX11': 'yes'
                     }
config['bitbucket.org'] = {'User': 'hg'}

config['topsecret.server.com'] = {'Host Port': '50022', 'ForwardX11': 'no'}

with open('example.ini', 'w') as configfile:  # 创建example.ini文件
    config.write(configfile)
           

结果:

(创建的文件如下)

example.ini

[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes

[bitbucket.org]
user = hg

[topsecret.server.com]
host port = 50022
forwardx11 = no
           

查找文件

import configparser

config = configparser.ConfigParser()

print("---------------------读取sections-------------------")
config.read('example.ini')
print(config.sections())  # 返回['bitbucket.org', 'topsecret.server.com'] 'DEFAULT'为默认 不打印
print("---------------------确认sections-------------------")
print('bitbucket.org' in config)  # 在里面返回True
print('baidu.com' in config)  # 不在里面返回False
print("------------------------取值------------------------")
print(config['DEFAULT']['serveraliveinterval'])  # 45
print(config['bitbucket.org']['user'])  # hg
print(config['topsecret.server.com']['host port'])  # 50022
print(config['bitbucket.org'])  # <Section: bitbucket.org>
print("-----------------------分隔符-----------------------")
for key in config['bitbucket.org']:  # 注意,先取bitbucket.org值 有DEFAULT会默认DEFAULT的键
    print(key)
print("-----------------------分隔符-----------------------")
print(config.options('bitbucket.org'))  # 同for循环,找到'bitbucket.org'下所有键
print(config.items('bitbucket.org'))  # 找到'bitbucket.org'下所有键值对
print(config.get('bitbucket.org', 'compression'))  # yes get方法Section下的key对应的value 没有就往DEFAULT中查找
print(config.get('bitbucket.org', 'user'))  # yes get方法Section下的key对应的value
           

结果:

---------------------读取sections-------------------

['bitbucket.org', 'topsecret.server.com']

---------------------确认sections-------------------

True

False

------------------------取值------------------------

45

hg

50022

<Section: bitbucket.org>

-----------------------分隔符-----------------------

user

serveraliveinterval

compression

compressionlevel

forwardx11

-----------------------分隔符-----------------------

['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']

[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]

yes

hg

Process finished with exit code 0

增删改操作

import configparser

config = configparser.ConfigParser()
config.read('example.ini')
config.add_section('yuan')  # 增加section
config.remove_section('bitbucket.org')  # 删除section
config.remove_option('topsecret.server.com', "forwardx11")  # 删除section中一项
config.set('topsecret.server.com', 'k1', '11111')  # 修改
config.set('yuan', 'k2', '22222')  # 修改
config.write(open('new2.ini', "w"))  # 写入新的文件
           

结果:

(修改后的文件创建如下)

new2.ini

[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes

[topsecret.server.com]
host port = 50022
k1 = 11111

[yuan]
k2 = 22222