## 读书笔记之 <<密码安全性>>
### 什么是密码哈希?
- 哈希算法: 将任何数量的数据转换为无法反转的固定长度的“指纹”(即使输入的变化很小,但生成的哈希值将完全不同)。
用于实现诸如哈希表之类的数据结构的哈希函数被设计为快速,不安全的。 仅加密哈希函数可用于实现密码哈希。 诸如SHA256,SHA512,RipeMD和WHIRLPOOL之类的哈希函数是加密哈希函数。
### 密码存储有几种方式:
- 直接存储密码明文m
- 存储密码明文的哈希值hash(m)
- 存储密码明文的加盐哈希 hash(m+salt),这里的salt可以是用户名,手机号等,但必须保证每个用户的salt都不一样才是安全的。
### 破解哈希:
- 尝试猜测密码(最简单的方法),对每个猜测进行哈希处理,并检查猜测的哈希是否等于被破解的哈希。 如果哈希值相等,则猜测为密码。
#### 猜测密码:
- 字典攻击: 使用的文件包含单词,词组,常用密码以及其他可能用作密码的字符串。文件中的每个单词都经过哈希处理,并将其哈希值与密码哈希值进行比较。 若匹配,则该单词为密码。这些字典文件是通过从大量文本甚至是密码的真实数据库中提取单词来构造的。
- 蛮力攻击(列举所有字符串) : 尝试所有可能的字符组合,直到给定的长度。 这种攻击在计算上非常昂贵,并且效率最低,但最终会找到密码。所以密码应该足够长,以至于搜索所有可能的字符串以找到它会花费很长时间。
- 注: 没有办法阻止字典攻击或蛮力攻击。 即可以使它们的有效性降低,但是没有办法完全阻止它们。 如果您的密码哈希系统是安全的,那么破解哈希的唯一方法是对每个哈希运行字典或蛮力攻击。
#### Tables
- 单纯地通过导入字典,采用和目标同等算法破解,其速度其实是非常缓慢的。之后通过大量的尝试和总结,发现若能够实现直接建立出一个数据文件,里面事先记录了采用和目标采用同样算法计算后生成的Hash散列数值,在需要破解的时候直接调用这样的文件进行比对,破解效率就可以大幅度地,甚至成百近千近万倍地提高,这样事先构造的Hash散列数据文件在安全界被称之为Table表(文件)。
#### 查找表
- 一种非常有效的方法,可以非常快速地破解许多相同类型的哈希。总体思路是在密码字典中预先计算密码的哈希值,并将它们及其对应的密码存储在查找表数据结构中。 一个好的查找表可以实现即使包含数十亿个哈希,也可以每秒处理数百个哈希查找。
#### 反向查询表
- 这种方式可以让攻击者不需要预先计算一个查询表的情况下同时对大量hash进行字典和暴力破解攻击。首先,攻击者会根据从数据库获取到的数据制作一个密码和用户名(一对多)对应的hash表。然后将常见的字典密码进行hash之后,跟这个表的hash进行对比,就可以知道用哪些用户使用了这个密码。这种攻击方式很有效果,因为通常情况下很多用户都会有使用相同的密码。
#### 彩虹表(Rainbow Table)
- 不是密码-->明文 的简单存储,以时间换空间。是现在破解哈希常用的办法。
(一) Rainbow Table的原理
- 存储所有的明文-密码所需要空间太大,因此提出了一种以计算时间降低存储空间的办法:“预计算的哈希链集”。
(二) 预计算的哈希链集
- 例如: 一条k=2哈希链: aaaaaa--->(H)281DAF40--->(R)sgfnyd--->(H)920ECF10--->(R)kiebgt
- H函数就是要破解的哈希函数。约简函数R是构建这条链的时候定义的一个函数:它的值域和定义域与H函数相反。通过该函数可以将哈希值约简为一个与原文相同格式的值。
- 这条链是这样生成的:随机选择一个明文aaaaaa,对其求哈希得到281DAF40,R(281DAF40) 得到另外一个明文sgfnyd。,继续重复2,3步骤,存储的时候,不需要存储所有的节点,只需要存储每条链的头尾节点(这里是aaaaaa和kiebgt),以大量的随机明文作为起节点,通过上述步骤计算出哈希链并将终节点进行储存,可得到一张哈希链集。
(三) 预计算的哈希链集的使用
- 要破解一个hash值:
(1) 假设其刚好是920ECF10:首先对其进行一次R运算,得到kiebgt,然后发现刚好命中了哈希链集中的(aaaaaa,kiebgt)链条。可以确定其极大概率在这个链条中。于是从aaaaaa开始重复哈希链的计算过程,发现sgfnyd的哈希结果刚好是920ECF10,于是破解成功。
(2) 密文不是“920ECF10”而是“281DAF40”:第一次R运算后的结果并未在末节点中找到,则再重复一次H运算+R运算,这时又得到了末节点中的值“kiebgt”。于是再从头开始运算,可知aaaaaa刚好可哈希值为281DAF40。
(3) 如是重复了k(=2)次之后,仍然没有在末节点中找到对应的值,则破解失败。
(四) 预计算的哈希链集的意义
- 对于一个长度为k的预计算的哈希链集,每次破解计算次数不超过k,因此比暴力破解大大节约时间。
- 每条链只保存起节点和末节点,储存空间只需约1/k,因而大大节约了空间。
### 加盐
- 通过在散列之前将一个随机字符串(称为salt)附加或添加到密码上来使哈希随机化。salt通常与哈希一起存储在用户帐户数据库中,或者作为哈希字符串本身的一部分存储在用户帐户数据库中。仅通过将散列随机化,查找表,反向查找表和Rainbow表就失效了。因为攻击者不会预先知道salt,因此他们无法预先计算查找表或彩虹表。若每个用户的密码都用不同的salt进行哈希处理,则反向查找表攻击也将不起作用。
### 盐实现错误:
(一) 盐再利用
- 一个常见的错误是在每个哈希中使用相同的盐。盐要么被硬编码到程序中,要么被随机生成一次。 这是无效的,因为如果两个用户使用相同的密码,则它们仍将具有相同的哈希值。 攻击者仍然可以使用反向查找表攻击对每个哈希同时运行字典攻击。 他们只需要在对每个密码猜测进行哈希处理之前就应用盐。如果将盐硬编码为流行产品,则可以为该盐建立查找表和彩虹表,以使其更容易破解该产品生成的哈希。因此每次用户创建帐户或更改密码时,都必须生成新的随机盐。
(二) 短盐
- 如果盐太短,攻击者可以为每种可能的盐建立查找表。
- 用户名不应该用作盐。 用户名对于单个服务可能是唯一的,但是它们是可预测的,并且经常被其他服务上的帐户重用。攻击者可以为常见的用户名建立查找表,并使用它们来破解用户名盐渍的哈希。
- 为了使攻击者无法为每种可能的盐创建查找表,盐必须很长。一个好的经验法则是使用与哈希函数输出大小相同的盐。例如,SHA256的输出为256位(32字节),因此盐值至少应为32个随机字节。
### 如何正确地哈希
#### 用盐散列
- 应使用加密安全的伪随机数生成器 (CSPRNG)生成盐。
- 盐值必须是每个用户每个密码唯一的。每次用户创建帐户或更改密码时,都应使用新的随机盐对密码进行哈希处理。切勿重复使用盐。盐也需要很长,以便有很多可能的盐。根据经验,盐至少与哈希函数的输出一样长。盐应与哈希一起存储在用户帐户表中。
#### 储存密码
- 使用CSPRNG生成长随机盐。
- 将盐添加到密码中,并使用标准密码哈希函数(例如Argon2,bcrypt,scrypt或PBKDF2)对其进行哈希处理。
- 将盐和哈希值都保存在用户的数据库记录中。
#### 验证密码
- 从数据库中检索用户的盐和哈希值。
- 将盐添加到给定的密码之前,并使用相同的哈希函数对其进行哈希处理。
- 将给定密码的哈希值与数据库中的哈希值进行比较。如果它们匹配,则密码正确。否则,密码错误。
参考资料:
- https://www.jianshu.com/p/732d9d960411
- http://www.ha97.com/4009.html
本文探讨了密码安全性的关键方面,包括密码哈希的原理、存储方式,以及破解策略如字典攻击、蛮力攻击。强调了使用加盐哈希的重要性,并指出盐的生成和长度对安全的影响。正确哈希密码应使用独特的随机盐,并结合使用Argon2、bcrypt等强哈希函数。
3711

被折叠的 条评论
为什么被折叠?



