1. 程式人生 > >【Flask】Flask實現密碼儲存安全性的兩種方式

【Flask】Flask實現密碼儲存安全性的兩種方式

密碼儲存安全性

網際網路上的大多使用者都會在不同的網站使用相同的密碼,如果某個網站把密碼以明文方式儲存在資料庫裡,又不幸地被攻擊者獲取了資料庫的訪問許可權,那後果不堪設想(比如號稱中國最大IT社群的某DN脫褲門事件,搞得我要單獨記一個密碼)

要想保護使用者的密碼,就不能明文儲存密碼,也不能用可從密文恢復原文的加密方式。那就要使用雜湊演算法的單向加密方法對密碼進行加密。單向加密意味著資料被加密之後,就不可能通過密文反向計算原文。但是雜湊演算法只是生成資料的摘要,所以相同的資料會生成相同的密文,版本控制工具Git就是通過SHA-1對檔案生成快照來進行內容變化追蹤

我們可以把密碼的雜湊值儲存起來,然後在使用者登入的時候,使用相同的雜湊演算法對輸入的密碼進行計算,並比較計算出的雜湊值與儲存在資料庫中的雜湊值是否相同。這樣就算攻擊者獲得了資料庫的訪問許可權,他們也得不到使用者的原密碼,不過可能會有其他隱私的洩露問題,這個只能靠相關網站的良心了,大家注意不要把自己的隱私儲存在網站上,永遠記得不要相信網際網路(的安全性)

雜湊演算法有很多種,但是大多數不安全,常用的比如MD5和SHA1。現在MD5已經不推薦使用了,隨便在網上搜一下就有各種“MD5線上破解”,如果還有網站用MD5加密,那這個網站已經沒人管了,死翹翹了。SHA1雖然被Google破解了,但是一般人還是別想了,所以SHA-1已經可以滿足需求了

給一個2017年2月23日Google發表的一篇破解SHA-1的論文給出的資料

  • md5:只需要一個智慧手機30秒就破解了
  • sha-1 shattered:110GPU 需要一年
  • sha-1 bruteforce:12000000GPU 需要一年

使用Werkzeug

Werkzeug中的security模組可以很方便的實現雜湊值的計算,只需要兩個函式,分別用於使用者註冊和使用者驗證階段

  • generate_password_hash(password,method=pbkdf2:sha1,salt_length=8):這個函式將原始密碼作為輸入,以字串形式輸出密碼的雜湊值。method和salt_length的預設值能滿足大多數需求

  • check_password_hash(hash,password):這個函式引數是雜湊值和使用者輸入的密碼。返回值為True表示密碼正確

下面例子是SQLAlchemyUser模型

from werkzeug.security import generate_password_hash, check_password_hash

class
User(db.model):
password_hash = db.Column(db.String()) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password)

set_password()方法在使用者註冊的時候使用,會呼叫generate_password_hash()並將password引數傳給它,將它的返回值儲存在列屬性password_hash

check_password()方法在使用者驗證的時候使用,會呼叫check_password_hash()並將資料庫儲存的雜湊值和使用者輸入的密碼傳給它,並返回它的返回值,如果是True則表示密碼正確

使用Flask-Bcrypt

Bcrypt被故意設計成計算起來低效而緩慢,從而使暴力破解變得更加困難,同樣也有兩個方法,方法名跟werkzeug.security一樣

安裝Flask-Bcrypt

pip install Flask-Bcrypt

首先建立Bcrypt物件,並加到app物件中

from flask_bcrypt import Bcrypt

bcrypt = Bcrypt()

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config_name)

    bcrypt.init_app(app)

然後讓User物件使用Bcrypt

from app import bcrypt

class User(db.model):
    password_hash = db.Column(db.String())

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

推薦使用Bcrypt,MD5、SHA的演算法速度太快了,那為什麼會因為Bcrypt慢就使用它?

因為Bcrypt採用了一系列不同的Blowfish加密演算法,並引入了一個work factor,這個工作因子可以讓你決定這個演算法的代價有多大。所以這個演算法不會因為計算機CPU處理速度變快了,而導致演算法的時間會縮短了。因為你可以增加work factor來降低其效能

那麼Bcrypt到底有多慢?

如果和MD5比較,Bcrypt使用值為12work factor加密“cool”。Bcrypt需要0.3秒,而MD5只需要一微秒(百萬分之一秒)。也就是說,如果說MD5加密的口令的只需要40秒就可以窮舉完所有的可能的,而使用Bcrypt需要12年