python內建模組之hashlib

2021-07-01 19:17:17 字數 3900 閱讀 1008

python的hashlib提供了常見的摘要演算法,如md5,sha1等等。

什麼是摘要演算法呢?摘要演算法又稱雜湊演算法、雜湊演算法。它通過乙個函式,把任意長度的資料轉換為乙個長度固定的資料串(通常用16進製制的字串表示)。

舉個例子,你寫了一篇文章,內容是乙個字串'how to use python hashlib - by michael',並附上這篇文章的摘要是'2d73d4f15c0db7f5ecb321b6a65e5d6d'。如果有人篡改了你的文章,並發表為'how to use python hashlib - by bob',你可以一下子指出bob篡改了你的文章,因為根據'how to use python hashlib - by bob'計算出的摘要不同於原始文章的摘要。

可見,摘要演算法就是通過摘要函式f()對任意長度的資料data計算出固定長度的摘要digest,目的是為了發現原始資料是否被人篡改過。

摘要演算法之所以能指出資料是否被篡改過,就是因為摘要函式是乙個單向函式,計算f(data)很容易,但通過digest反推data卻非常困難。而且,對原始資料做乙個bit的修改,都會導致計算出的摘要完全不同。

我們以常見的摘要演算法md5為例,計算出乙個字串的md5值:

import hashlib

md5 = hashlib.md5()

md5.update('how to use md5 in python hashlib?')

print md5.hexdigest()

計算結果如下:

d26a53750bc40b38b65a520292f69306
如果資料量很大,可以分塊多次呼叫update(),最後計算的結果是一樣的:

md5 = hashlib.md5()

md5.update('how to use md5 in ')

md5.update('python hashlib?')

print md5.hexdigest()

試試改動乙個字母,看看計算的結果是否完全不同。

md5是最常見的摘要演算法,速度很快,生成結果是固定的128 bit位元組,通常用乙個32位的16進製制字串表示。

另一種常見的摘要演算法是sha1,呼叫sha1和呼叫md5完全類似:

import hashlib

sha1 = hashlib.sha1()

sha1.update('how to use sha1 in ')

sha1.update('python hashlib?')

print sha1.hexdigest()

sha1的結果是160 bit位元組,通常用乙個40位的16進製制字串表示。

比sha1更安全的演算法是sha256和sha512,不過越安全的演算法越慢,而且摘要長度更長。

有沒有可能兩個不同的資料通過某個摘要演算法得到了相同的摘要?完全有可能,因為任何摘要演算法都是把無限多的資料集合對映到乙個有限的集合中。這種情況稱為碰撞,比如bob試圖根據你的摘要反推出一篇文章'how to learn hashlib in python - by bob',並且這篇文章的摘要恰好和你的文章完全一致,這種情況也並非不可能出現,但是非常非常困難。

摘要演算法能應用到什麼地方?舉個常用例子:

任何允許使用者登入的**都會儲存使用者登入的使用者名稱和口令。如何儲存使用者名稱和口令呢?方法是存到資料庫表中:

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 = 

def login(user, password):

pass

採用md5儲存口令是否就一定安全呢?也不一定。假設你是乙個黑客,已經拿到了儲存md5口令的資料庫,如何通過md5反推使用者的明文口令呢?暴力破解費事費力,真正的黑客不會這麼幹。

'e10adc3949ba59abbe56e057f20f883e': '123456'

'21218cca77804d2ba1922c33e0151105': '888888'

'5f4dcc3b5aa765d61d8327deb882cf99': 'password'

這樣,無需破解,只需要對比資料庫的md5,黑客就獲得了使用常用口令的使用者賬號。

對於使用者來講,當然不要使用過於簡單的口令。但是,我們能否在程式設計上對簡單口令加強保護呢?

由於常用口令的md5值很容易被計算出來,所以,要確保儲存的使用者口令不是那些已經被計算出來的常用口令的md5,這一方法通過對原始口令加乙個複雜字串來實現,俗稱「加鹽」:

def calc_md5(password):

return get_md5(password + 'the-salt')

經過salt處理的md5口令,只要salt不被黑客知道,即使使用者輸入簡單口令,也很難通過md5反推明文口令。

但是如果有兩個使用者都使用了相同的簡單口令比如123456,在資料庫中,將儲存兩條相同的md5值,這說明這兩個使用者的口令是一樣的。有沒有辦法讓使用相同口令的使用者儲存不同的md5呢?

如果假定使用者無法修改登入名,就可以通過把登入名作為salt的一部分來計算md5,從而實現相同口令的使用者也儲存不同的md5。

練習:根據使用者輸入的登入名和口令模擬使用者註冊,計算更安全的md5:

db = {}

def register(username, password):

db[username] = get_md5(password + username + 'the-salt')

然後,根據修改後的md5演算法實現使用者登入的驗證:

def login(username, password):

pass

摘要演算法在很多地方都有廣泛的應用。要注意摘要演算法不是加密演算法,不能用於加密(因為無法通過摘要反推明文),只能用於防篡改,但是它的單向計算特性決定了可以在不儲存明文口令的情況下驗證使用者口令。

原文

python內建模組之random模組

import random print random.random 隨機 0 1 浮點數 print random.uniform 1,10 隨機指定範圍的浮點數 print random.randint 1,3 隨機整數1 3,包括3 print random.randrange 1,3 1 3隨...

python內建模組之XML模組

xml和json 一樣都是可以跨平台的,只是xml相比較,老一點 import xml.etree.elementtree as et a et.parse first xml.xml 載入乙個檔案 root a.getroot print root 乙個xml檔案 print root.tag x...

python內建模組之re模組

在python要想使用正則必須借助於模組,re就是其中之一 查詢字串中所有匹配到的字元,並返回乙個列表,沒有匹配資料則返回乙個空列表 import re re.findall 正規表示式 帶匹配的文字 根據正則匹配除所有符合條件的資料 res re.findall b eva jason jacks...