zmo*_*mol 56 php security passwords hash salt
我正在看一些我自己没有写过的代码.代码尝试使用SHA512散列密码并仅使用time()
盐作为密码.是time()
太简单盐这或者是这个代码安全吗?
感谢您的回答和评论.我将在此为新读者总结一下:
random, evenly distributed, high entropy
盐?好吧,那么我用随机字符串32 char long替换time()怎么样.可以通过在一组字母表字符上循环32次来生成随机字符串.听起来不错吗?
Jac*_*cco 84
不,time()
不是好盐.
从我对Salt Generation和开源软件的回答中复制而来
什么是盐?
salt是固定长度的随机字节集,添加到散列算法的输入中.
为什么盐渍(或播种)哈希有用?
向散列添加随机盐可确保相同的密码将产生许多不同的散列.salt通常与散列函数的结果一起存储在数据库中.由于以下几个原因,对哈希进行盐析是很好的:
- 腌制大大增加了预计算攻击的难度/成本(包括彩虹表)
- Salting确保相同的密码不会产生相同的哈希值.这可确保您无法确定两个用户是否具有相同的密码.而且,更重要的是,您无法确定同一个人是否在不同系统中使用相同的密码.
Salting增加了密码的复杂性,从而大大降低了Dictionary和Birthday攻击的有效性.(如果盐这是唯一真正被存储从哈希分开).- 适当的腌制大大增加了预计算攻击的存储需求,直至它们不再实用.(8个字符区分大小写的字母数字密码,16位盐,散列到128位值,在 没有彩虹减少的情况下,将占用不到200 艾字节).
盐不需要保密.
salt不是一个秘密密钥,而是通过使哈希函数特定于每个实例来使"盐"起作用.使用salted哈希,没有一个哈希函数,但每个可能的盐值都有一个哈希函数.这可以防止攻击者攻击N个散列密码的次数少于攻击一个密码的N倍.这是盐的重点.
"秘密盐"不是盐,它被称为"密钥",它意味着您不再计算哈希值,而是计算消息验证码(MAC).计算MAC是一项棘手的业务(比简单地将一个键和一个值拼接到一个哈希函数中要复杂得多)并且它完全是一个非常不同的主题.对于使用它的每个实例,盐必须是随机的.这可确保攻击者必须分别攻击每个salted哈希.
如果你依赖你的盐(或盐算算法)是秘密的,你进入安全通过晦涩的领域(将无法工作).最有可能的是,你没有从盐保密中获得额外的安全性; 你只是得到了温暖的模糊安全感.因此,它不会让您的系统更安全,而只会让您远离现实.
那么,为什么盐必须是随机的?
从技术上讲,盐应该是独一无二的.对于每个散列密码,salt的要点是不同的.这意味着全世界.由于没有按需分配独特盐的中央组织,我们必须依靠下一个最好的东西,即使用不可预测的随机发生器进行随机选择,最好是在足够大的盐空间内使碰撞不可能(使用相同的两个实例)盐值).
尝试从一些"大概是唯一的"数据中获取盐是很诱人的,例如用户ID,但是由于一些令人讨厌的细节,这些方案经常会失败:
如果您使用例如用户ID,则攻击不同系统的一些坏人可能只汇集其资源并为用户ID 1到50创建预先计算的表.用户ID在系统范围内是唯一的,但不是全球性的.
这同样适用于用户名:每个Unix系统都有一个"root",但世界上有很多根."root"的彩虹表值得付出努力,因为它可以应用于数百万个系统.更糟糕的是,那里还有很多"bob",很多人没有系统管理员培训:他们的密码可能很弱.
唯一性也是暂时的.有时,用户会更改密码.对于每个新密码,必须选择新的盐.否则,攻击者获得旧密码的哈希值,并且新的哈希值可能会同时攻击两者.
使用从加密安全,不可预测的PRNG获得的随机盐可能是某种矫枉过正,但至少它可以证明可以保护您免受所有这些危害.这不是为了防止攻击者知道单个盐是什么,而是为了不给他们提供大量,可用于大量潜在目标的大目标.随机选择使目标尽可能薄.
结论:
使用随机,均匀分布的高熵盐.无论何时创建新密码或更改密码,都要使用新的盐.将盐与散列密码一起存储.喜欢大盐(至少10个字节,最好是16个或更多).
盐不会将错误的密码变成好的密码.它只是确保攻击者至少为他打破的每个错误密码支付字典攻击价格.
有用的资料来源:
stackoverflow.com:用于密码哈希的非随机盐
Bruce Schneier:实用密码学(书籍)
Matasano安全性:足够使用Rainbow Tables
usenix.org:自1976年以来Unix crypt使用盐
owasp.org:为什么要加盐
openwall.com:盐免责声明:
我不是安全专家.(虽然这个答案由Thomas Pornin审查)
如果有任何安全专业人员发现错误,请评论或编辑此维基答案.
至于什么似乎是你的随机盐的良好来源
还读:什么是随机数生成最安全的种子?
在没有专用的,基于硬件的随机生成器的情况下,获取随机数据的最佳方法是询问操作系统(在Linux上,这被称为/dev/random
或/dev/urandom
[两者都有优点和问题,选择你的毒药];在Windows上,调用CryptGenRandom()
)
如果由于某种原因你无法访问上面提到的随机源,在PHP中你可以使用以下函数:
来自phpass v0.3的源码
<?php
/**
* Generate pseudo random bits
* @copyright: public domain
* @link http://www.openwall.com/phpass/
* @param int $length number of bits to generate
* @return string A string with the hexadecimal number
* @note don't try to improve this, you will likely just ruin it
*/
function random_bits($entropy) {
$entropy /= 8;
$state = uniqid();
$str = '';
for ($i = 0; $i < $entropy; $i += 16) {
$state = md5(microtime().$state);
$str .= md5($state, true);
}
$str = unpack('H*', substr($str, 0, $entropy));
// for some weird reason, on some machines 32 bits binary data comes out as 65! hex characters!?
// so, added the substr
return substr(str_pad($str[1], $entropy*2, '0'), 0, $entropy*2);
}
?>
Run Code Online (Sandbox Code Playgroud)