Python中使用hashlib模組處理演算法的教程

來源:互聯網
上載者:User
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 hashlibmd5 = 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 hashlibsha1 = 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 | 123456bob   | abc999alice  | alice2008

如果以明文儲存使用者口令,如果資料庫泄露,所有使用者的口令就落入駭客的手裡。此外,網站營運人員是可以訪問資料庫的,也就是能擷取到所有使用者的口令。

正確的儲存口令的方式是不儲存使用者的明文口令,而是儲存使用者口令的摘要,比如MD5:

username | password---------+---------------------------------michael | e10adc3949ba59abbe56e057f20f883ebob   | 878ef96e86145580c38c87f0410ad153alice  | 99b1c2188db85afee403b1536010c2c9

當使用者登入時,首先計算使用者輸入的明文口令的MD5,然後和資料庫儲存的MD5對比,如果一致,說明口令輸入正確,如果不一致,口令肯定錯誤。

練習:根據使用者輸入的口令,計算出儲存在資料庫中的MD5口令:

def calc_md5(password):  pass

儲存MD5的好處是即使營運人員能訪問資料庫,也無法獲知使用者的明文口令。

練習:設計一個驗證使用者登入的函數,根據使用者輸入的口令是否正確,返回True或False:

db = {  'michael': 'e10adc3949ba59abbe56e057f20f883e',  'bob': '878ef96e86145580c38c87f0410ad153',  'alice': '99b1c2188db85afee403b1536010c2c9'}def login(user, password):  pass

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

考慮這麼個情況,很多使用者喜歡用123456,888888,password這些簡單的口令,於是,駭客可以事先計算出這些常用口令的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

小結

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

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.