穷举法
大多数系统在保存用户密码时采用MD5等算法进行加密,原理是通过明文进行MD5计算后,将密文与数据库保存的密文进行比较,以14位数字和英文结合的密码来看,共有1.24*10^25中结果,假设电脑每秒钟可以计算10亿次,最差的结果也需要4亿年才能完成。
数据字典
数据字典通过收集大部分常见的密码明文和哈希值,在获取到加密后的哈希值时,通过查询字典来找到对应的明文,以14位数字和英文结合的密码来看,生成32位哈希字符串的对照表需要14TB的存储空间。
彩虹表
对一个明文p0进行H计算(MD5等Hash算法),通过构造一个R函数,对哈希值进行伪逆运算,得到p1。
将p1重复进行H-R运算得到pn。存储p0和pn对,这样得到一个类似数据字典的表,存储空间大大减小。
假设得到一串加密后的Hash码,对Hash码进行一次R运算,得到p,将p与表里所有pn进行比对,如果找到则说明p=pn,否则对p进行一次H-R运算,将结果再与所有pn进行比对,如果找到,说明p=p(n-1),因为我们是进行了一次H-R运算才匹配到pn的,所以对应p(n-1)的位置。
知道p(n-1)等于明文后,由于我们保存了p0,所以可以从p0开始算,算到p(n-1)处得到明文,如果和所有pn进行比对后还是找不到,则进行2次H-R运算,以此类推。
这样得到一张由多个p0pn组成的链表称为哈希链表,并不算真正的彩虹表。
上图中,从加粗部分的"vfkkd"开始,两个哈希值进行R运算得到了相同的明文,后续的H-R运算将计算出相同的值,这样将导致两条链条上能保存的数据量出现大量重复,增加破解时校验的重复性,破解时间被延长。
于是需要对R函数进行改进,在不同阶段,使用不同的R函数,如下图:
即使在"vfkkd"处,进行R运算得到了相同的明文,由于位置不一样,后续使用的R函数也不一样,计算出来的结果也不是重复的,理论上,两条链条可能在同一个节点出现相同的明文,导致后续所有结果都一致,即使这样,由于两条链条的pn节点也完全一致,我们可以舍弃其中一条,这种R1...Rk多个不同的R函数就像由内而外不同颜色的彩虹一样,称为彩虹表。
防御彩虹表攻击
目前防御彩虹表攻击可以通过加salt,延长密码明文字符串的长度,即使破解出明文,也无法得知哪一部分是密码原文,哪一部分是salt值,例如采用Bcrypt算法,通过在明文的随机位置加salt,每次Hash的结果都不相同。