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

Sch*_*hof 9 python linux crypt cryptography

首先,上下文:我正在尝试创建一个需要登录的基于命令行的工具(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)
Run Code Online (Sandbox Code Playgroud)

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

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

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

Fed*_*oni 7

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'
Run Code Online (Sandbox Code Playgroud)

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

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


HUA*_*UAH 5

对于 crypt 模块的使用:

当生成加密密码时,您需要提供盐。只要满足列出的条件,也可以随机增加对暴力破解的抵抗力。检查密码时,您应该提供 getpwname 中的值,以防您所在的系统支持更大的盐大小并且您自己没有生成它。

普通的留言:

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

string_to_hash = user.stored_salt + entered_password
successful_login = (sha1(string_to_hash) == user.stored_password_hash)
Run Code Online (Sandbox Code Playgroud)

更新:虽然这对于彩虹表来说更加安全,但上述方法仍然存在加密弱点。正确应用 HMAC 算法可以进一步提高您的安全性,但超出了我的专业知识范围。

  • 更喜欢 PBKDF2 来保存密码:使用 HMAC 应用盐并迭代 (2认同)