在python中使用salt并哈希密码

时间:2012-03-07 00:34:04

标签: python authentication hash passwords salt

这段代码应该用盐哈希密码。 salt和哈希密码正在保存在数据库中。密码本身不是。

鉴于手术的敏感性,我想确保一切都是洁净的。

注意:我习惯使用url安全版的b64encode。

import hashlib
import base64
import uuid

password = 'test_password'
salt     = base64.urlsafe_b64encode(uuid.uuid4().bytes)


t_sha = hashlib.sha512()
t_sha.update(password+salt)
hashed_password =  base64.urlsafe_b64encode(t_sha.digest())

9 个答案:

答案 0 :(得分:47)

根据这个问题的其他答案,我使用bcrypt实现了一种新方法。

为什么要使用bcrypt

如果我理解正确,使用bcrypt超过SHA512的论点是bcrypt设计得很慢。 bcrypt还可以选择在第一次生成哈希密码时调整您希望的速度:

# The '12' is the number the dictates the 'slowness'
bcrypt.hashpw(password, bcrypt.gensalt( 12 ))

慢是可取的,因为如果恶意方获取包含散列密码的表,那么对它们进行解密则要困难得多。

实施

def get_hashed_password(plain_text_password):
    # Hash a password for the first time
    #   (Using bcrypt, the salt is saved into the hash itself)
    return bcrypt.hashpw(plain_text_password, bcrypt.gensalt())

def check_password(plain_text_password, hashed_password):
    # Check hased password. Useing bcrypt, the salt is saved into the hash itself
    return bcrypt.checkpw(plain_text_password, hashed_password)

注释

我能够使用以下方法在Linux系统中轻松安装该库:

pip install py-bcrypt

但是,我在Windows系统上安装它时遇到了更多麻烦。它似乎需要一个补丁。请参阅此Stackoverflow问题:py-bcrypt installing on win 7 64bit python

答案 1 :(得分:46)

聪明的事情不是自己编写加密,而是使用像passlib这样的东西:https://bitbucket.org/ecollins/passlib/wiki/Home

以安全的方式编写加密代码很容易。令人讨厌的是,对于非加密代码,当程序崩溃时,它会在它无法正常工作时立即注意到它。使用加密代码时,您通常只能在迟到之后发现并且您的数据已被泄露。因此,我认为最好使用由其他人知道的关于该主题并且基于战斗测试协议的其他人编写的包。

另外,passlib还有一些不错的功能,使其易于使用,并且如果旧的协议被破坏,也很容易升级到更新的密码散列协议。

同样只有一轮sha512更容易受到字典攻击。 sha512设计得很快,这在尝试安全存储密码时实际上是一件坏事。其他人对所有这些问题都进行了长时间的考虑,所以你最好利用这一点。

答案 2 :(得分:38)

编辑:这个答案错了​​。不要使用加密哈希来存储密码。使用密码哈希。


我很好看。但是,我很确定你实际上并不需要base64。你可以这样做:

import hashlib, uuid
salt = uuid.uuid4().hex
hashed_password = hashlib.sha512(password + salt).hexdigest()

如果它不会造成困难,您可以通过将salt和哈希密码存储为原始字节而不是十六进制字符串来在数据库中获得稍高效的存储。为此,请将hex替换为bytes,将hexdigest替换为digest

答案 3 :(得分:19)

为了在Python 3中工作,你需要UTF-8编码,例如:

hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()

否则你会得到:

  

追踪(最近的呼叫最后):
    文件“”,第1行,在中       hashed_pa​​ssword = hashlib.sha512(密码+盐).hexdigest()
  TypeError:必须在散列之前对Unicode对象进行编码

答案 4 :(得分:8)

如果您需要使用现有系统存储的哈希值,那么

passlib似乎很有用。如果您可以控制格式,请使用像bcrypt或scrypt这样的现代哈希。这时,bcrypt似乎更容易从python中使用。

passlib支持bcrypt,它建议将py-bcrypt安装为后端:http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html

如果您不想安装passlib,也可以直接使用py-bcrypt。自述文件有基本用法的例子。

另见:How to use scrypt to generate hash for password and salt in Python

答案 5 :(得分:6)

我不喜欢'想要复活一个旧线程,但......任何想要使用现代最新安全解决方案的人都要使用argon2。

https://pypi.python.org/pypi/argon2_cffi

它赢得了密码哈希竞争。 (https://password-hashing.net/)它比bcrypt更容易使用,并且比bcrypt更安全。

答案 6 :(得分:0)

首先导入:-

import hashlib, uuid

然后根据您的方法更改此代码:

uname = request.form["uname"]
pwd=request.form["pwd"]
salt = hashlib.md5(pwd.encode())

然后在数据库sql查询中传递此盐和名称,在登录名下方是表名:

sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"

答案 7 :(得分:0)

从Python 3.4开始,标准库中的hashlib模块包含key derivation个函数,这些函数“被设计用于安全密码散列”

因此,将hashlib.pbkdf2_hmac之类的盐与os.urandom生成的盐一起使用:

from typing import Tuple
import os
import hashlib
import hmac

def hash_new_password(password: str) -> Tuple[bytes, bytes]:
    """
    Hash the provided password with a randomly-generated salt and return the
    salt and hash to store in the database.
    """
    salt = os.urandom(16)
    pw_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    return salt, pw_hash

def is_correct_password(salt: bytes, pw_hash: bytes, password: str) -> bool:
    """
    Given a previously-stored salt and hash, and a password provided by a user
    trying to log in, check whether the password is correct.
    """
    return hmac.compare_digest(
        pw_hash,
        hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    )

# Example usage:
salt, pw_hash = hash_new_password('correct horse battery staple')
assert is_correct_password(salt, pw_hash, 'correct horse battery staple')
assert not is_correct_password(salt, pw_hash, 'Tr0ub4dor&3')
assert not is_correct_password(salt, pw_hash, 'rosebud')

请注意:

  • 使用16字节盐和PBKDF2的100000迭代与Python文档中建议的最小数量相匹配。进一步增加迭代次数将使散列的计算速度变慢,因此更加安全。
  • os.urandom始终使用加密安全的随机源
  • is_correct_password中使用的
  • hmac.compare_digest基本上只是用于字符串的==运算符,但没有短路能力,这使其不受定时攻击的影响。那个probably doesn't really provide any extra security value,但也没有伤害,所以我继续使用它。

有关如何使密码散列良好的理论以及适用于对密码进行散列的其他功能的列表,请参见https://security.stackexchange.com/q/211/29805

答案 8 :(得分:0)

这是我的提议:

for i in range(len(rserver.keys())):
    salt = uuid.uuid4().hex
    print(salt)
    mdp_hash = rserver.get(rserver.keys()[i])
    rserver.set(rserver.keys()[i], hashlib.sha256(salt.encode() + mdp_hash.encode()).hexdigest() + salt)
    rsalt.set(rserver.keys()[i], salt)