我是否正确实现了密码的哈希与加盐?
密码哈希加盐代码的问题与数据库存储方案
代码问题修正
你的代码存在核心缺陷:生成的随机盐没有和哈希值一起留存,后续验证密码时无法复用相同的盐,导致无法正确校验密码。以下是修正后的代码,同时添加了密码验证逻辑:
import hashlib import os password = input("Create Password: ") def hash_new_password(password): # 生成16字节的随机盐 salt = os.urandom(16) # 基于PBKDF2-HMAC生成密码哈希 hash_result = hashlib.pbkdf2_hmac('blake2b', password.encode('utf-8'), salt=salt, iterations=100000) # 将盐和哈希值转为十六进制字符串,用$分隔后返回 return f"{salt.hex()}${hash_result.hex()}" def verify_password(stored_credential, input_password): # 拆分存储的盐和哈希值 salt_hex, stored_hash = stored_credential.split('$') salt = bytes.fromhex(salt_hex) # 用相同参数生成输入密码的哈希 input_hash = hashlib.pbkdf2_hmac('blake2b', input_password.encode('utf-8'), salt=salt, iterations=100000) # 用常量时间比较避免时序攻击 return hashlib.compare_digest(input_hash.hex(), stored_hash) # 生成带盐的哈希凭证 hashed_credential = hash_new_password(password) print(hashed_credential) # 验证示例(可注释掉) # is_valid = verify_password(hashed_credential, input("Enter Password to Verify: ")) # print("Password Valid:", is_valid)
数据库存储方案
有两种常见的存储方式,按需选择:
方式一:单字段存储拼接字符串
- 在数据库表中创建一个字段(比如
hashed_password),字段类型设为VARCHAR(255)(长度足够容纳盐和哈希的十六进制字符串)。 - 将
hash_new_password返回的拼接字符串(格式为盐十六进制$哈希十六进制)直接存入该字段。 - 验证时,从数据库取出该字段值,传入
verify_password函数即可。
方式二:双字段分别存储
- 在数据库表中创建两个字段:
salt:类型VARCHAR(64),存储盐的十六进制字符串;password_hash:类型VARCHAR(256),存储哈希值的十六进制字符串。
- 存储时,拆分
hash_new_password返回的字符串,将盐和哈希值分别存入对应字段。 - 验证时,取出两个字段的值,拼接成
盐$哈希格式的字符串,再传入verify_password函数,或者直接修改验证函数接收盐和哈希两个参数。
注意事项
- 绝对不要存储明文密码,只留存盐和哈希值。
- 字段长度不要设置过短,避免截断盐或哈希值导致验证失败。
- 验证时必须使用常量时间比较(如代码中的
hashlib.compare_digest),防止时序攻击泄露信息。
内容的提问来源于stack exchange,提问作者NukaWinter
相关产品推荐
相关产品推荐

