常规的加解密方案一般是直接将通过公钥和明文加密后的密文存储到数据库中,但是如果私钥和密文泄露之后,很容易解密出原始密文。
为了确保安全性,我们可以采用一套严谨的密码处理流程,主要分为以下三步:
-
前端加密 (RSA):用户输入的密码在发送到服务器前,会先使用 RSA 公钥进行加密-。这可以防止密码在传输过程中被窃听。
-
后端解密与哈希 :服务器收到 RSA 加密的密码后,会使用私钥将其解密为明文。随后,后端会立即使用 Werkzeug 库 的
generate_password_hash单向哈希函数,将这个明文密码转换成一个哈希值。 -
数据库存储 :最后,只有这个单向哈希后的密码会被存储到数据库中。
与常规加解密的不同之处在于,用户密码数据库存储时并不直接存储加密后的密文,而是存储一个用generate_password_hash 单向哈希生成后的密码,校验时则使用check_password_hash 将数据库的密码哈希值与用户的密码进行比对校验,校验通过则说明密码正确。
当用户登录时,系统会将用户输入的密码进行同样的哈希处理,然后与数据库中存储的哈希值进行比对。由于哈希函数的单向性,即使私钥和数据库被泄露,攻击者也难以从哈希值逆推出原始密码,从而保证了用户密码的安全。
python
import base64
import os
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_OAEP
from pathlib import Path
from werkzeug.security import check_password_hash, generate_password_hash
current_dir = os.path.abspath(os.path.dirname(__file__))
private_key_path = os.path.join(current_dir, 'private.pem')
public_key_path = os.path.join(current_dir, 'public.pem')
def encrypt(line: str) -> str:
rsa_key = RSA.importKey(Path(public_key_path).read_text(), "Welcome")
cipher = PKCS1_OAEP.new(rsa_key)
password_base64 = base64.b64encode(line.encode('utf-8')).decode('utf-8')
encrypted_password = cipher.encrypt(password_base64.encode())
return base64.b64encode(encrypted_password).decode('utf-8')
def decrypt(line: str) -> str:
rsa_key = RSA.importKey(open(private_key_path).read(), "Welcome")
cipher = PKCS1_OAEP.new(rsa_key)
return cipher.decrypt(base64.b64decode(line)).decode()
if __name__ == '__main__':
# 原始密码
raw_password = "12345678"
print("raw_password", raw_password)
# 加密后用于安全传输的密文
encrypt_password = encrypt(raw_password)
print("encrypt_password", encrypt_password)
# 解密后的 base64 编码的密码
base64_decrypt_password = decrypt(encrypt_password)
print("base64_decrypt_password", base64_decrypt_password)
# 解密后的明文
decrypt_password = base64.b64decode(base64_decrypt_password).decode('utf-8')
print("decrypt_password", decrypt_password)
# base64 密码生成的 hash
hash_password = generate_password_hash(base64_decrypt_password)
print("hash_password", hash_password)
# hash 密码与 base64 密码进行校验
check_result = check_password_hash(hash_password, base64_decrypt_password)
print("check_password", check_result)
python
raw_password 12345678
encrypt_password hy6nRk5p08YZiKPQwumUv09h3pHziRiUgRfO40QCZiV4UIJDZZfHii+8GEtP+IJlrc+Q0Vl/ZMs41dLbp7Efj2VWZStVzB/nbqsRUdeej+KYc6yLAr0pnexw9MvJzQjbgLBRIiHPrT8jDmrsKUtaZMyPy71BPzewaQhHN888Nuk=
base64_decrypt_password MTIzNDU2Nzg=
decrypt_password 12345678
hash_password scrypt:32768:8:1$08LI2OVO1I6YjPPs$4be22ea1b39b667ce2fa084c2c2e0f444d217688fbdb5572189395e436ea402bdeb7de4d875d0cc913e2ca81b054f4e291bdb293d4c525de821bfb8a3672a9bf
check_password True