1.Hash与Hash碰撞
Hash,简单来讲,是一种将任意长度的输入变换成固定长度的输出,固定长度的输出在“实际应用场景”下可以代表该输入。Hash函数通常被翻译成散列函数。Hash通常用来校验信息的一致性。
Hash函数的实现多种多样,在安全领域应用最为广泛的是SHA-x系列和MDx系列。Hash函数也划分为带密钥的Hash函数和不带密钥的Hash函数,通常所说的Hash函数是不带密钥的Hash函数。这里对Hash算法的实现原理不做更多的探讨。
篇外补充:
Hash
函数的定义和性质
|
由于Hash固定长度输出的特性,必然会存在多个不同输入产生相同输出的情况。如果两个输入串的hash函数的值一样,则称这两个串是一个碰撞(Collision)。在理论范围内,存在一个输出串对应无穷多个输入串,所以碰撞具有其必然性。
如果找到碰撞,那么意味着我们可以破坏信息的一致性而不被接收方察觉,搜寻指定输入的Hash碰撞值的过程被称作“Hash破解”。这里需要说明的
是,Hash函数必须是不可逆的,所以不存在从散列值到原始输入的破解(这里不包括暴力破解,使用彩虹表是暴力破解的最佳方式,但是仍然无法保证破解到的
数据是原始数据)。设计不良的Hash算法,很容易让人找到碰撞值,例如(参考网址:http://www.laruence.com/2011/12
/30/2435.html):
“
在PHP中,如果键值是数字, 那么Hash的时候输入值就是数字本身, 一般的时候都是, index & tableMask. 而tableMask是用来保证数字索引不会超出数组可容纳的元素个数值, 也就是数组个数-1.
PHP的Hashtable的大小都是2的指数, 比如如果你存入10个元素的数组, 那么数组实际大小是16, 如果存入20个,
则实际大小为32, 而63个话, 实际大小为64. 当你的存入的元素个数大于了数组目前的最多元素个数的时候, PHP会对这个数组进行扩容,
并且从新Hash.
现在, 我们假设要存入64个元素(中间可能会经过扩容, 但是我们只需要知道, 最后的数组大小是64,
并且对应的tableMask为63:0111111), 那么如果第一次我们存入的元素的键值为0, 则hash后的值为0, 第二次我们存入64,
hash(1000000 & 0111111)的值也为0, 第三次我们用128, 第四次用192…
”
一个“优良”的hash函数 f 应当满足以下三个条件:
- 任意y,找x,使得f(x)=y,非常困难。
- 给定x1,找x2,使得f(x1)=f(x2),非常困难。
- 找x1,x2,使得f(x1)=f(x2),非常困难。
上面的“非常困难”的意思是除了枚举外不可能有别的更快的方法。几乎所有的寻找碰撞的方法都从第三条入手,即找到两个不一样的输入得到相同的输出。
寻找Hash碰撞的方法也很多如用于一般性攻击的生日攻击和模差分法,用于攻击具有分组链结构的Hash方案的中间相遇攻击,于攻击基于模算术的Hash函数的修正分组攻击。这里我简要介绍以下四种寻找碰撞的方法:
“相等子串法”是针对某些Hash函数具有相同的字符串组合在上下文中相同位置的Hash值都相同的特性来构造碰撞的。比如
f(“string1”)=f(“string2”),那么字符串“aaastring1bbb”与字符串“aaastring2bbb”
中,“string1”与“string2”具有相同的Hash值。针对这个特性我们可以构造任意多的碰撞,比如“Ly”和“nz”的Hash值相同,那
么“LyLy”、“nznz”、“Lynz”、“nzLy”的Hash值都相同。
“生日攻击法”,生日攻击方法没有利用Hash函数的结构和任何代数弱性质,它只依赖于消息摘要的长度,即Hash值的长度。这种攻击对Hash函数提出
了一个必要的安全条件,即消息摘要必须足够长。生日攻击这个术语来自于所谓的生日问题,在一个教室中最少应有多少学生才使得至少有两个学生的生日在同一天
的概率不小于1/2?这个问题的答案为23。下面详细描述生日攻击的方法。
设
h
:
X->Y
是一个
Hash
函数,
X
和
Y
都是有限的,并且
|X|>=2|Y|
,记
|X|=m
,
|Y|=n
。显然至少有
n
个碰撞,问题是如何去找到这些碰撞。一个很自然的方法是随机选择
k
个不同的元素
x1,x2,x3,
••••••
,xk
∈
X,
计算
yI=h(xi)
,
1<=i<=k
,然后确定是否有一个碰撞发生。这个过程类似于把
k
个球随机地扔到
n
个箱子里边,然后检查看是否某一箱子里边至少有两个球。
k
个球对应于
k
个随机数
x1,x2,x3,
••••••
,xk
,
n
个箱子对应于
Y
中的
n
个可能的元素。我们将计算用这种方法找到一个碰撞的概率的下界,该下界只依赖于
k
和
n
,而不依赖于
m
。
|
因为我们关心的是碰撞概率的下界,所以可以假定对所有
y
∈
Y
,有
|h-1(y)|
≈
m/n
。这个假定是合理的,这是因为如果原像集
h-1(y)( y
∈
Y)
不是近似相等的,那么找到一个碰撞的概率将增大。
|
因为原像集
h-1(y)( y
∈
Y)
的个数都近似相等,并且
xI(1<=i<=k)
是随机选择的,所以可将
yI=h(xi)
,
1<=i<=k
视作
Y
中的随机元素(
yi(1<=i<=k)
未必不同)。但计算
k
个随机元素
y1,y2,
••••••
yk
∈
Y
是不同的概率是一件容易的事情。依次考虑
y1,y2,
••••••
yk
。
y1
可任意地选择;
y2
≠
y1
的概率为
1-1/n
;
y3
≠
y1 ,y2
的概率为
1-2/n
;••••••;
yk
≠
y1,y2,
••••••
,yk-1
的概率为
1-(k-1)/n
。
|
因此,没有碰撞的概率是(
1-1/n
)
(1-2/n
)••••••
(1-(k-1)/n
)。如果
x
是一个比较小的实数,那么
1-x
≈
e-x
,这个估计可由下式推出:
e-x=1-x+x2/2!-x3/3!+
••••••
。现在估计没有碰撞的概率(
1-1/n
)
(1-2/n
)••••••
(1-(k-1)/n
)约为
1-e-k(k-1)/2n
。我们设ε是至少有一个碰撞的概率,则ε≈
1-e-k(k-1)/2n
,从而有
k2-k
≈
nln(1/(1-
ε
)2)
。去掉
-k
这一项,我们有
k2
≈
nln(1/(1-
ε
)2)
,即
k
≈
sqrt(2nln(1/(1-
ε
)2))
。
|
如果我们取ε
=0.5
,那么
k
≈
1.17 sqrt(n)
。这表明,仅
sqrt(n)
个
X
的随机的元素就能以
50%
的概率产生一个碰撞。注意ε的不同选择将导致一个不同的常数因子,但
k
与
sqrt(n)
仍成正比例。
|
如果
X
是一个教室中的所有学生的集合,
Y
是一个非闰年的
365
天的集合,
h(x)
表示学生
x
的生日,这时
n=365
,ε
=0.5
,由
k
≈
1.17 sqrt(n)
可知,
k
≈
22.3
。因此,此生日问题的答案为
23
。
|
生日攻击隐含着消息摘要的长度的一个下界。一个
40
比特长的消息摘要是很不安全的,因为仅仅用
220
(大约一百万)次随机
Hash
可至少以
1/2
的概率找到一个碰撞。为了抵抗生日攻击,通常建议消息摘要的长度至少应取为
128
比特,此时生日攻击需要约
264
次
Hash
。安全的
Hash
标准的输出长度选为
160
比特是出于这种考虑。
|
“中间相遇法”是生日攻击的一种变形,它不比较Hash值,而是比较链中的中间变量。这种攻击主要适用于攻击具有分组链结构的Hash方案。中间相遇攻击的基本原理为:将消息分成两部分,对伪造消息的第一部分从初试值开始逐步向中间阶段产生r1
个变量;对伪造消息的第二部分从Hash结果开始逐步退回中间阶段产生r2
个变量。在中间阶段有一个匹配的概率与生日攻击成功的概率一样。
“模差分法”是山东大学王小云教授提出的Hash分析方法,具有较高的执行效率。模差分的算法请参考http://wenku.baidu.com/view/f0bf451414791711cc7917b5.html?from=related
。
2.HashTable与HashTable退化
上面我们了解了Hash函数的特性和Hash攻击的可行性。我在这里没有详细说明攻击的算法细节,也没有给出具体的代码实现,因为这些不是本文要关注的重
点,之后如果有机会我会专门讨论Hash攻击的各种方案及代码实现。下面我们来了解和Hash函数密切相关的数据结构—HashTable(参考内容:http://en.wikipedia.org/wiki/Hash_table
)。
HashTable(散列表,也叫哈希表),是一种根据键值(key-value)进行直接访问的数据结构。
HashTable结合了链表和数组的双向优势,所以增、删、改、查各种操作速度都很快。在HashTable中,Hash函数的作用是通过Key得到
Value的地址(数组的下标),这和我们前面说到的在安全领域保证数据完整性的Hash算法的功能有所区别,因为要返回的是数组下标,所以Hash值必
须是整数。因此信息安全领域的标准Hash算法在这里就无用武之地了,不同的应用开发平台通常实现自己的Hash算法,或者使用在HashTable构造
算法中常用的Hash函数,比如DJBX33A算法。
前面我们说话Hash无法避免Hash碰撞的问题,那么HashTable如何处理碰撞问题呢,通常有两种做法:开放定址法,链接法。
开放定址法(Open
addressing)这种方法就是在计算一个key的哈希的时候,发现目标地址已经有值了,即发生冲突了,这个时候通过相应的函数在此地址后面的地址去
找,直到没有冲突为止。这个方法常用的有线性探测,二次探测,再哈希。这种解决方法有个不好的地方就是,当发生冲突之后,会在之后的地址空间中找一个放进
去,这样就有可能后来出现一个key哈希出来的结果也正好是它放进去的这个地址空间,这样就会出现非同义词的两个key发生冲突。
链接法(Separate chaining)链接法是通过数组和链表组合而成的。当发生冲突的时候只要将其加到对应的链表中即可。如图1-2.
图1-2
与开放定址法相比,链接法有如下几个优点:
①链接法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
②由于链接法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
③开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而链接法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
④在用链接法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。而对开放地址法构造的散列表,删除结点不能简单地将被
删结点的空间置为空,否则将截断在它之后填人散列表的同义词结点的查找路径。这是因为各种开放地址法中,空地址单元(即开放地址)都是查找失败的条件。因
此在 用开放地址法处理冲突的散列表上执行删除操作,只能在被删结点上做删除标记,而不能真正删除结点。
当然链接法也有其缺点,拉链法的缺点是:指针需要额外的空间,故当结点规模较小时,开放定址法较为节省空间,而若将节省的指针空间用来扩大散列表的规模,可使装填因子变小,这又减少了开放定址法中的冲突,从而提高平均查找速度。
以链接法为例,如果每次插入的值都产生碰撞,那么HashTable最终就变成了一个链表,我们称之为HashTable退化。如图1-3.
图1-3
HashTable退化成一个链表之后,性能会急剧的下降。
3.拒绝服务攻击
HashTable在所有的Web应用框架上都有应用,我们对Web应用每次发起请求所提交的参数,服务器端都会将其存储在HashTable中供后台代
码调用。比如在Asp.NET应用中,我们使用Request.Form[key]和Request.QueryString[key]的方式来获取客户
端提交的参数,参数就是被存储在HashTable中的,我们传入参数名称作为Key,通过Hash函数转换成对应的Value的数组下标,然后
Value值被返回。
在正常的应用场景下这没什么问题,现在我们回到上面提到的HashTable退化的问题,如果客户端根据Web应用框架采用的Hash函数来通过某
种Hash攻击的方式获得大量的碰撞,那么HashTable就会退化成链表,服务器有可能处理一次请求要花上十几分钟甚至几个小时的时间,一台PC机就
可以搞定一台服务器,根本不用分布式攻击。当然攻击能否成功的先决条件是Web应用框架采用的Hash机制存在漏洞。如果存在这样的漏洞,攻击者可以轻而
易举的实施拒绝服务攻击。
下面我们来看看现实世界中,流行的Web框架对HashTable退化的防御能力。(参考内容:
http://www.nruns.com/_downloads/advisory28122011.pdf
)
3.1 PHP5
PHP5的HashTable使用的函数是DJBX33A。
DJBX33A
算法,也叫
time33
算法,它是
php
、
apache,
、
perl
、
bsddb
的默认
Hash
算法。
|
下面的代码体现了
DJBX33A
算法的基本思想
uint32_t time33(char const *str, int len)
{
unsigned long hash = 0;
for (int i = 0; i < len; i++) {
hash = hash *33 + (unsigned long) str[i];
}
return hash;
}
|
对于为什么使用
33
这个数,有这样的解释:
1到256之间的所有奇数,都能达到一个可接受的哈希分布,平均分布大概是86%。而其中33,17,31,63,127,129这几个数在面对大量的哈希运算时有一个更大的优势,就是这些数字能将乘法用位运算配合加减法替换,这样运算速度会更高。并不是所有基于DJBX33A
的算法都使用
33
作为倍数,
如Ngix使用的是time31,Tokyo Cabinet使用的是time37。
|
PHP版本的DJBX33A
算法如下所示:
inline unsigned time33(char const*str, int len)
{
unsigned long hash = 5381;
/* variant with the hash unrolled eight times */
for (; len >= 8; len -= 8) {
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
hash = ((hash << 5) + hash) + *str++;
}
switch (len) {
case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */
case 1: hash = ((hash << 5) + hash) + *str++; break;
case 0: break;
}
return hash;
}
|
对于DJBX33A算法,我们完全可以通过上面提到的“相等子串法”来找到碰撞,进行攻击。
目前PHP官方建议通过配置来限制表单提交的最大长度来抵御该攻击。
3.2 ASP.NET
Asp.NET使用Request.Form对象来获取表单提交的变量。内部的Hash函数是DJBX33X(Dan Bernstein's times 33, XOR)。
DJBX33X算法思想如下所示:
static ulong DJBX33X (char *arKey, uint nKeyLength)
{
ulong h = 5381;
char *arEnd = arKey + nKeyLength;
while (arKey < arEnd) {
h += (h << 5);
h ^= (ulong) *arKey++;
}
return h;
}
针对DJBX33X算法的特点,我们可以采用上面提到的中间相遇攻击的方法来寻找碰撞。
微软已经发布了针对该漏洞的补丁,如果您担心该漏洞会对您的网站造成麻烦,请更新补丁。
3.3 Java
Java 的Hash函数是对DJBX33A的改造(使用的31而不是33,另外初始值为0而不是5381),但我们仍然可以使用相等子串法来获取该Hash函数的碰撞。
基于Java的Tomcat服务器存在这样的漏洞。
3.4 其他
Python、Ruby和V8同样有这样的漏洞。
出处:http://www.cnblogs.com/xuanhun/
分享到:
相关推荐
hashcat密钥碰撞,无需安装,CMD下执行即可。CMD下执行即可。
MurmurHash算法由Austin Appleby创建于2008年,现已应用到Hadoop、libstdc 、nginx、libmemcached,Redis,Memcached,Cassandra,HBase,Lucene等开源系统。2011年Appleby被Google雇佣,随后Google推出其变种的...
"分布式拒绝服务攻击防御技术综述" 分布式拒绝服务攻击防御技术是当前网络安全领域的热点话题。随着网络攻击的日益增长,分布式拒绝服务攻击(DDoS)已经对网络安全造成了极大的威胁。因此,分布式拒绝服务攻击防御...
标题中的“Hash Collision DoS漏洞:web实例”指的是在Web应用程序中出现的一种安全问题,即哈希碰撞拒绝服务攻击(Hash Collision Denial of Service)。这种攻击利用了哈希表(Hash Table)数据结构的特性,当两个...
但是,哈希碰撞的存在意味着恶意攻击者可能通过碰撞攻击找到一个不同但能产生相同哈希值的密码,因此需要选择安全性高的哈希函数,如SHA-256或bcrypt。 "Hash.exe"工具可能提供了以下功能: 1. 计算文件或文本的...
本文指出,Geohash编码的推理通道源于其明文信息与实际地理位置之间的关联性。通过对k近邻查询响应的统计分析,攻击者可以推测出密文Geohash的原始值,实现近似重构。具体来说,攻击者可以利用前缀匹配的结果,逐步...
### 哈希碰撞与生日攻击 #### 一、哈希碰撞是什么? 哈希(Hash)是一种算法,用于将任意长度的数据映射为固定长度的值。这些值通常称为哈希值或摘要。哈希算法的一个重要特性是,对于任何给定的输入,其输出始终...
hash函数与消息认证讲义 包括 5.1 Hash函数概述 5.1.1 Hash函数定义 5.1.2 Hash函数的安全性 5.1.3 Hash函数的迭代构造法 5.2 Hash函数MD5 5.2.1 MD5算法 5.2.2 MD5的安全性 5.3 安全Hash算法SHA-1 5.3.1 SHA-1...
#### 一、HASH函数简介与应用场景 随着信息技术的发展,尤其是互联网时代的到来,网络安全成为了至关重要的研究领域。在这个背景下,HASH函数作为一种关键的技术手段,被广泛应用于保障数据完整性和消息认证。其...
- **SHA-1 (Secure Hash Algorithm 1)**:产生160位的哈希值,比MD5更安全,但同样面临碰撞攻击的威胁。 - **SHA-256 (Secure Hash Algorithm 256)**:SHA-2家族的一员,产生256位的哈希值,安全性更高,广泛用于...
3. 防止中间人攻击:在进行文件传输时,如果网络被中间人攻击,攻击者可能篡改文件并同时更改提供的Hash值,所以应直接从可信源获取Hash值。 总的来说,Hash值校验工具是确保数据完整性和安全性的利器,通过其便捷...
在实际工程应用中,三维Hashin失效准则通常与有限元分析结合,对复杂结构的复合材料进行模拟。这需要将失效准则嵌入到求解器中,通过迭代求解应力和应变场,判断材料在各个位置是否达到失效状态。这种方法既考虑了...
UTHASH 是一个开源的 C 语言库,提供了一种简单且高效的哈希表实现,用于在 C 代码中快速查找和管理数据结构。这个库的主要功能是提供一个宏定义的集合,可以方便地将结构体转化为哈希表,进而进行添加、删除、查找...
6. **计算方法**:在实际应用中,3D Hashin准则通常与有限元分析结合,通过对材料的微结构进行模拟,计算每个单元的失效状态,并确定整个结构的整体失效。 7. **应用范围**:3D Hashin准则广泛应用于航空航天、汽车...
标题中的"HASHIN.rar_ABAQUS_Hashin失效准则 abaqus_abaqus hashin_abaqus 三维Hashi"表明这是一个关于ABAQUS软件中应用Hashin失效准则进行三维分析的示例或教程。ABAQUS是一款广泛应用的有限元分析软件,尤其在结构...
标题 "UMAT_Hashin3D_hashin" 指涉的是一个专门针对复合材料损伤分析的三维子程序,该程序基于Hashin破坏准则。在有限元分析(FEA)中,用户自定义材料(User-Defined Material,UMAT)是实现特定材料行为建模的一种...
3. **比较验证**: 用户可以将计算出的Hash值与原始或信任源提供的Hash值进行对比。如果两者相同,那么文件就未被修改;若不同,则可能存在数据损坏或篡改。 在日常工作中,Hash值检测工具常用于以下场景: - **...
例如,当你从互联网上下载一个大文件时,服务提供者通常会提供文件的哈希值,你可以使用Hash 1.04 对下载后的文件进行哈希计算,然后与提供的哈希值进行对比。如果两者匹配,说明文件在传输过程中没有被篡改或损坏,...