Python使用bcrypt?或?Passlib?對(duì)系統(tǒng)用戶密碼進(jìn)行哈希和驗(yàn)證處理操作
在設(shè)計(jì)一個(gè)系統(tǒng)的時(shí)候,肯定都有會(huì)有用戶身份認(rèn)證的問題,一般對(duì)用戶校驗(yàn)的時(shí)候,都是對(duì)用戶存在數(shù)據(jù)庫(kù)總的密碼哈希值進(jìn)行判斷,從而避免密碼泄露和反向解密,那么在Python 開發(fā)中,我們可以引入bcrypt 或 Passlib 對(duì)系統(tǒng)用戶密碼進(jìn)行哈希和驗(yàn)證處理,以及介紹使用其他類庫(kù)實(shí)現(xiàn)常規(guī)加解密處理操作。本篇隨筆主要介紹bcrypt 和 Passlib 它們之間的差異,以及在實(shí)際使用中的一些代碼供參考。
1、bcrypt 和 Passlib的介紹
bcrypt
和 Passlib
都是用于密碼哈希和驗(yàn)證的 Python 庫(kù),但它們有一些顯著的區(qū)別:
bcrypt:
bcrypt
是一個(gè)專門用于實(shí)現(xiàn)bcrypt
哈希算法的庫(kù)。它相對(duì)簡(jiǎn)單,專注于單一功能,即對(duì)密碼進(jìn)行bcrypt
哈希處理和驗(yàn)證。- 適合只需要
bcrypt
哈希算法的場(chǎng)景。 - 提供的 API 簡(jiǎn)單直接,功能較少。
Passlib:
Passlib
是一個(gè)更高級(jí)的密碼哈希庫(kù),它支持多種哈希算法(如bcrypt
、PBKDF2
、Argon2
等),并且提供了更豐富的功能。- 適合需要支持多種密碼哈希算法和策略的場(chǎng)景。
- 提供的
CryptContext
類可以方便地管理和遷移多個(gè)哈希算法。還提供了密碼哈希的自動(dòng)升級(jí)機(jī)制,以及對(duì)舊算法的棄用處理。
當(dāng)你確定只需要使用 bcrypt
算法,并且不需要額外的復(fù)雜功能時(shí),bcrypt
是一個(gè)合適的選擇。它適合簡(jiǎn)單的項(xiàng)目,或者在需要直接控制 salt
等參數(shù)的情況下使用。
Passlib 適合復(fù)雜的項(xiàng)目,尤其是需要支持多個(gè)哈希算法或需要遷移哈希算法的場(chǎng)景。適合需要長(zhǎng)期維護(hù)的項(xiàng)目,因?yàn)樗峁┝烁嗟呐渲煤桶踩δ堋?/p>
bcrypt: 靈活性較低,因?yàn)樗恢С?nbsp;bcrypt
算法。沒有多種哈希算法選擇或密碼策略管理功能。使用簡(jiǎn)單,代碼更直觀。如果你只需要 bcrypt
算法,bcrypt
庫(kù)可能更容易上手。
Passlib:提供了很高的靈活性和擴(kuò)展性。可以根據(jù)需要切換和配置不同的哈希算法,管理復(fù)雜的密碼策略。通過(guò) CryptContext
,可以輕松管理不同算法之間的過(guò)渡。功能強(qiáng)大但相對(duì)復(fù)雜,需要更深入的學(xué)習(xí)和理解。但它的高層 API 設(shè)計(jì)得很友好,一旦熟悉,可以簡(jiǎn)化很多常見任務(wù)。CryptContext
是其中一個(gè)用于管理多個(gè)哈希算法和密碼哈希策略的類。
示例代碼對(duì)比:
bcrypt 使用示例:
import bcrypt password = b"supersecretpassword" hashed = bcrypt.hashpw(password, bcrypt.gensalt()) # 驗(yàn)證密碼 if bcrypt.checkpw(password, hashed): print("Password matches!") else: print("Password does not match.")
Passlib 使用示例:
from passlib.context import CryptContext # 創(chuàng)建一個(gè) CryptContext 對(duì)象 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # 哈希密碼 password = "my_secret_password" hashed_password = pwd_context.hash(password) print("Hashed password:", hashed_password) # 驗(yàn)證密碼 is_correct = pwd_context.verify(password, hashed_password) if is_correct: print("密碼正確") else: print("密碼錯(cuò)誤")
定義了一個(gè) CryptContext
對(duì)象,用于管理密碼哈希算法。schemes=["bcrypt"]
表示你要使用 bcrypt
算法,而 deprecated="auto"
表示自動(dòng)管理過(guò)時(shí)的哈希方案。
使用 pwd_context.hash()
方法對(duì)密碼進(jìn)行哈希處理。每次生成的哈希值都是唯一的,即使是相同的密碼也會(huì)生成不同的哈希值。
使用 pwd_context.verify()
方法可以驗(yàn)證給定的密碼與存儲(chǔ)的哈希值是否匹配。
你還可以在創(chuàng)建 CryptContext
對(duì)象時(shí)傳遞更多參數(shù)來(lái)定制密碼哈希行為,這種方法可以增強(qiáng)密碼存儲(chǔ)的安全性。例如:
pwd_context = CryptContext( schemes=["bcrypt"], bcrypt__rounds=12 # bcrypt 的哈希輪數(shù),默認(rèn)為 12 )
2、使用指定的salt進(jìn)行加密
在 Passlib
中,bcrypt
算法默認(rèn)會(huì)自動(dòng)生成一個(gè)隨機(jī)的 salt
,這也是 bcrypt
的一種安全特性。如果你想使用指定的 salt
進(jìn)行加密,需要注意的是,Passlib
并不直接支持通過(guò)指定 salt
來(lái)進(jìn)行哈希處理,因?yàn)檫@可能會(huì)降低安全性。
不過(guò),如果你確實(shí)需要使用指定的 salt
進(jìn)行哈希處理,你可以使用以下的方式:
手動(dòng)拼接
salt
和密碼:可以手動(dòng)拼接salt
和密碼,然后對(duì)結(jié)果進(jìn)行哈希處理。但這種方法僅適用于了解風(fēng)險(xiǎn)并確保安全措施的場(chǎng)景。使用
bcrypt
庫(kù):直接使用bcrypt
庫(kù)進(jìn)行處理,它允許你傳遞一個(gè)指定的salt
。不過(guò),注意這會(huì)有一定的安全風(fēng)險(xiǎn)。
1) 使用bcrypt 庫(kù)指定 salt
如果你確實(shí)需要指定 salt
,可以使用 bcrypt
庫(kù)。
import bcrypt # 指定的 salt(必須為 16 字節(jié),前綴為 b"$2b$") salt = bcrypt.gensalt(rounds=12) # 或者使用自定義的 16 字節(jié) salt print(f"Generated salt: {salt}") # 要加密的密碼 password = "my_secret_password" # 使用指定的 salt 進(jìn)行加密 hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt) print(f"Hashed password: {hashed_password}")
2) 手動(dòng)拼接 salt 和密碼
如果你使用 Passlib
,并想使用指定的 salt
,可以手動(dòng)拼接 salt
和密碼,然后對(duì)這個(gè)組合結(jié)果進(jìn)行哈希處理。這個(gè)方式一般不建議使用,因?yàn)樗茐牧?nbsp;bcrypt
的安全設(shè)計(jì)原則。
from passlib.context import CryptContext # 創(chuàng)建一個(gè) CryptContext 對(duì)象 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # 自定義 salt custom_salt = "my_custom_salt" # 拼接 salt 和密碼 password = "my_secret_password" password_with_salt = custom_salt + password # 對(duì)拼接后的字符串進(jìn)行哈希處理 hashed_password = pwd_context.hash(password_with_salt) print("Hashed password with custom salt:", hashed_password)
注意事項(xiàng)
- 使用固定的
salt
會(huì)降低密碼哈希的安全性,因?yàn)橄嗤?nbsp;salt
和相同的密碼會(huì)生成相同的哈希值。 bcrypt
的設(shè)計(jì)初衷是讓每次生成的salt
都不同,以此提高安全性。- 如果你需要在特定的場(chǎng)景下使用固定的
salt
,一定要確保你的系統(tǒng)有足夠的其他安全措施。
同一密碼,每次獲得的hash值都會(huì)不同,那么有些人會(huì)問,如果通過(guò)pwd_context.hash獲得的hash值,下一次能夠?qū)Ρ日_嗎?
回答是的,使用 pwd_context.hash()
生成的哈希值可以在后續(xù)對(duì)比中正確匹配,即使每次生成的哈希值看起來(lái)不同。Passlib
和 bcrypt
的設(shè)計(jì)確保了這一點(diǎn)。
自動(dòng)生成的
salt
:每次你使用pwd_context.hash()
生成一個(gè)新的哈希值時(shí),bcrypt
都會(huì)自動(dòng)生成一個(gè)隨機(jī)的salt
并將其嵌入到生成的哈希值中。因此,即使對(duì)同一個(gè)密碼進(jìn)行多次哈希,每次生成的哈希值也會(huì)不同。驗(yàn)證過(guò)程:在驗(yàn)證過(guò)程中,
pwd_context.verify()
會(huì)自動(dòng)從存儲(chǔ)的哈希值中提取salt
并重新計(jì)算哈希,然后將其與提供的哈希值進(jìn)行比較。這意味著,即使哈希值不同,驗(yàn)證仍然能夠成功匹配。
即使你每次運(yùn)行 pwd_context.hash(password)
得到的哈希值不同(因?yàn)?nbsp;salt
不同),pwd_context.verify(password, hashed_password)
仍然會(huì)返回 True
,表示密碼驗(yàn)證成功。
3、加密和解密處理
Passlib
主要用于密碼哈希處理,并不支持加密和解密操作。如果你需要對(duì)字符串進(jìn)行加密和解密,或者使用非對(duì)稱加密,你需要使用其他庫(kù),例如 cryptography
或 PyCryptodome
。
1)對(duì)稱加密和解密
對(duì)于對(duì)稱加密,你可以使用 cryptography
庫(kù)中的 Fernet
,它是基于 AES 算法的加密方案。
安裝 cryptography
庫(kù)
pip install cryptography
對(duì)稱加密和解密示例
from cryptography.fernet import Fernet # 生成密鑰(注意:密鑰需要安全存儲(chǔ)) key = Fernet.generate_key() cipher = Fernet(key) # 加密 message = "This is a secret message" encrypted_message = cipher.encrypt(message.encode()) print("Encrypted:", encrypted_message) # 解密 decrypted_message = cipher.decrypt(encrypted_message).decode() print("Decrypted:", decrypted_message)
2) 非對(duì)稱加密和解密
對(duì)于非對(duì)稱加密,你可以使用 cryptography
庫(kù)中的 RSA
算法。通常,非對(duì)稱加密用于加密較短的信息或加密對(duì)稱密鑰。
非對(duì)稱加密和解密示例
from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import serialization, hashes # 生成私鑰和公鑰 private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, ) public_key = private_key.public_key() # 加密 message = b"This is a secret message" encrypted_message = public_key.encrypt( message, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) print("Encrypted:", encrypted_message) # 解密 decrypted_message = private_key.decrypt( encrypted_message, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) print("Decrypted:", decrypted_message.decode())
3)保存和加載密鑰
保存私鑰:
private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() ) with open('private_key.pem', 'wb') as f: f.write(private_pem)
加載私鑰:
with open('private_key.pem', 'rb') as f: private_key = serialization.load_pem_private_key( f.read(), password=None, )
保存公鑰:
public_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) with open('public_key.pem', 'wb') as f: f.write(public_pem)
加載公鑰:
with open('public_key.pem', 'rb') as f: public_key = serialization.load_pem_public_key(f.read())
我們?cè)陂_發(fā)過(guò)程總,可以根據(jù)需求選擇合適的加密方式和庫(kù),并妥善管理密鑰。
到此這篇關(guān)于Python使用bcrypt 或 Passlib 對(duì)系統(tǒng)用戶密碼進(jìn)行哈希和驗(yàn)證處理 的文章就介紹到這了,更多相關(guān)Python用戶密碼哈希和驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 用python的哈希函數(shù)對(duì)密碼加密
- python 密碼學(xué)示例——理解哈希(Hash)算法
- Python驗(yàn)證用戶密碼是否規(guī)范腳本示例
- python?密碼驗(yàn)證(滑塊驗(yàn)證)
- 詳解Python中的自定義密碼驗(yàn)證
- Python實(shí)現(xiàn)破解網(wǎng)站登錄密碼(帶token驗(yàn)證)
- python實(shí)現(xiàn)三次密碼驗(yàn)證的示例
- python實(shí)現(xiàn)密碼驗(yàn)證合格程序的思路詳解
- Python使用selenium實(shí)現(xiàn)網(wǎng)頁(yè)用戶名 密碼 驗(yàn)證碼自動(dòng)登錄功能
相關(guān)文章
pymysql.err.DataError:1366的報(bào)錯(cuò)解決
通過(guò)python把數(shù)據(jù)同步至mysql數(shù)據(jù)庫(kù)的過(guò)程中,遇到錯(cuò)誤,本文主要介紹了pymysql.err.DataError:1366的報(bào)錯(cuò)解決,具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05Python 操作mysql數(shù)據(jù)庫(kù)查詢之fetchone(), fetchmany(), fetchall()用法示例
這篇文章主要介紹了Python 操作mysql數(shù)據(jù)庫(kù)查詢之fetchone(), fetchmany(), fetchall()用法,結(jié)合實(shí)例形式分析了Python使用pymysql模塊的fetchone(), fetchmany(), fetchall()方法進(jìn)行mysql數(shù)據(jù)庫(kù)查詢的操作技巧,需要的朋友可以參考下2019-10-10在Pycharm中項(xiàng)目解釋器與環(huán)境變量的設(shè)置方法
今天小編就為大家分享一篇在Pycharm中項(xiàng)目解釋器與環(huán)境變量的設(shè)置方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10python 基于pygame實(shí)現(xiàn)俄羅斯方塊
這篇文章主要介紹了python 基于pygame實(shí)現(xiàn)俄羅斯方塊的方法,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下2021-03-03python tornado上傳文件功能實(shí)現(xiàn)(前端和后端)
Tornado 是一個(gè)功能強(qiáng)大的 Web 框架,除了基本的請(qǐng)求處理能力之外,還提供了一些高級(jí)功能,在 Tornado web 框架中,上傳圖片通常涉及創(chuàng)建一個(gè)表單,讓用戶選擇文件并上傳,本文介紹tornado上傳文件功能,感興趣的朋友一起看看吧2024-03-03