编辑(2016年):按照偏好顺序使用Argon2, scrypt, bcrypt 或 PBKDF2。尽可能使用大的减速系数,根据您的情况而定。使用经过审核的现有实现。确保使用正确的盐(虽然您使用的库应该为您确保这一点)。
当您对密码进行哈希时,请
不要使用明文MD5。
使用
PBKDF2,这基本上意味着使用随机盐来防止
彩虹表攻击,并迭代(重新哈希)足够的次数以减慢哈希速度-不要让您的应用程序花费太长时间,但足够让攻击者暴力破解大量不同的密码。
从文档中:
- 至少迭代1000次,最好更多-计时实现以查看可行的迭代次数。
- 8字节(64位)的盐足以,而且随机数不需要安全(盐未加密,我们不担心有人会猜测它)。
- 在哈希时应用盐的好方法是使用HMAC和您喜欢的哈希算法,使用密码作为HMAC密钥,将盐用作要哈希的文本(请参见文档的this section)。
Python中的示例实现,使用SHA-256作为安全哈希:
编辑:正如Eli Collins所提到的,这不是PBKDF2实现。 您应该更喜欢坚持标准的实现,例如PassLib。
from hashlib import sha256
from hmac import HMAC
import random
def random_bytes(num_bytes):
return "".join(chr(random.randrange(256)) for i in xrange(num_bytes))
def pbkdf_sha256(password, salt, iterations):
result = password
for i in xrange(iterations):
result = HMAC(result, salt, sha256).digest()
return result
NUM_ITERATIONS = 5000
def hash_password(plain_password):
salt = random_bytes(8)
hashed_password = pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)
return salt.encode("base64").strip() + "," + hashed_password.encode("base64").strip()
def check_password(saved_password_entry, plain_password):
salt, hashed_password = saved_password_entry.split(",")
salt = salt.decode("base64")
hashed_password = hashed_password.decode("base64")
return hashed_password == pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)
password_entry = hash_password("mysecret")
print password_entry
check_password(password_entry, "mysecret")