繁体   English   中英

Python crypt模块 - 盐的正确使用是什么?

[英]Python crypt module — what's the correct use of salts?

首先,上下文:我正在尝试创建一个需要登录的基于命令行的工具(Linux)。 此工具的帐户与系统级帐户无关 - 这些帐户都不会查看/ etc / passwd。

我打算使用与/ etc / passwd相同的格式(大致)将用户帐户存储在文本文件中。

尽管没有使用系统级密码文件,但使用crypt似乎是一种很好的做法,而不是以明文形式存储密码。 (虽然crypt肯定比以明文形式存储密码更好,但我对其他方式持开放态度。)

我的隐藏知识基于此: https//docs.python.org/2/library/crypt.html

文档似乎要求一些不可能的东西:“建议在检查密码时使用完整的加密密码作为盐。”

咦? 如果我正在创建加密密码(如在创建用户记录时),我如何使用加密密码作为盐? 它还不存在。 (我假设你必须使用相同的盐来创建和检查密码。)

我曾尝试使用明文密码作为盐。 这确实有效,但有两个问题; 一个容易克服,一个严重:

1)明文密码的前两个字母包含在加密密码中。 您可以通过不将前两个字符写入文件来解决此问题:

user_record = '%s:%s:%s' % (user_name, crypted_pw[2:], user_type)

2)通过使用明文密码作为salt,您似乎可以减少系统中的熵量。 可能我误解了盐的目的。

我能够推导出的最佳实践是使用用户名中的前两个字符作为salt。 这是否合适,或者是否有一些我错过的东西让这个行动变得糟糕?

我对盐的理解是它可以防止从字典中预先计算密码哈希值。 我可以为所有密码使用标准盐(例如我的首字母缩写,“JS”),但对于攻击者而言,这似乎比使用每个用户的用户名中的两个字符要少。

Python的crypt()是系统的crypt()函数的包装器。 从Linux crypt()手册页:

char *crypt(const char *key, const char *salt);

key is a user’s typed password.
salt is a two-character string chosen from the set [a–zA–Z0–9./]. 
This string is used to perturb the algorithm in one of 4096 
different ways.

重点是“ 字符串”。 现在,如果你看看crypt()在Python中的行为:

>>> crypt.crypt("Hello", "World")
'Wo5pEi/H5/mxU'
>>> crypt.crypt("Hello", "ABCDE")
'AB/uOsC7P93EI'

你会发现结果的前两个字符总是与原盐的前两个字符重合,这确实形成了真正的双字符盐本身。 也就是说,crypt()的结果具有2char-salt + encrypted-pass形式。 因此,结果没有区别,如果不是传递双字符盐或原始的多字符盐,而是传递整个加密密码。

注意:集[a-zA-Z0-9./]包含64个字符,64 * 64 = 4096。 以下是两个字符与“ 4096种不同方式”的关系。

对于crypt模块的使用:

生成加密密码时,您提供盐。 只要满足列出的条件,增加对强力的抵抗力也可能是随机的。 在检查密码时,您应该提供getpwname中的值,以防您在支持更大盐大小且未自行生成的系统上。

普通的留言:

如果这与实际系统登录无关,则没有什么可以阻止您使用比crypt更强的方法。 您可以随机生成每用户盐的N个字符,并与SHA-1哈希中的用户密码组合使用。

string_to_hash = user.stored_salt + entered_password
successful_login = (sha1(string_to_hash) == user.stored_password_hash)

更新:虽然这对彩虹表更安全,但上述方法仍然存在加密缺陷。 正确应用HMAC算法可以进一步提高您的安全性,但超出了我的专业领域。

你误解了文档; 它表示由于salt的长度可能因底层的crypt()实现而异,因此在检查密码时应将整个加密密码作为salt值。 也就是说,不要将前两个字符拉成盐,而只是折腾整个事物。

你想让初始盐基于用户名的想法似乎没问题。

这里有一些关于盐渍密码的一般建议:

  1. 通常,使用盐来制造肘桌 ,计算成本太高。 因此,您应该为所有密码哈希添加一些随机盐,并将其存储在散列密码值旁边的纯文本中。
  2. 使用HMAC - 它是一个很好的标准,它比连接密码和盐更安全。
  3. 使用SHA1:MD5已损坏。 如果你知道这一点,那就没有违法行为。 ;)

不会让salt成为密码的函数。 攻击者必须生成彩虹表才能拥有密码的即时查找数据库,但他们只需要这样做一次。 如果你选择一个随机的32位整数,他们必须生成2 ^ 32个表,这些(与确定性盐不同)成本方式,太多的内存(和时间)。

对于某些增加的强度,您可以通过使用格式的salt来使crypt模块使用md5。

$1$ABCDEFGH$

ABCDEFGH是你的盐串。

>>> p = crypt.crypt('password', '$1$s8Ty3/f$')
>>> p
Out: '$1$s8Ty3/f$0H/M0JswK9pl3X/e.n55G1'
>>> p == crypt.crypt('password', p)
Out: True

(请注意,这是crypt的gnu扩展,请参阅linux系统上的“man crypt”)。 MD5(现在甚至是SHA1)可能会“损坏”,但它们对于密码哈希仍然相对较好,而md5仍然是linux本地密码的标准。

密码或从密码派生的任何内容都不应该用作salt。 特定密码的盐应该是不可预测的。

用户名或用户名的一部分是可以容忍的,但更好的是来自加密RNG的随机字节。

使用PBKDF2,在不同的线程上查看此注释 (包括Python实现)。

看看BjörnEdström 解释的文章TrueCrypt 它包含有关truecrypt如何工作的易于理解的解释以及一些truecrypt功能的简单Python实现, 包括密码管理

他在谈论Python crypt()模块,而不是Python中的TrueCrypt

Python 2中的默认crypt.crypt()不是很安全, 本文解释了更安全的替代方案可能如何工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM