百科问答小站 logo
百科问答小站 font logo



什么是哈希洪水攻击(Hash-Flooding Attack)? 第1页

  

user avatar   timothyqiu 网友的相关建议: 
      

你开了一家菜鸟驿站,代收周围几百个小区的所有包裹。因为每天的包裹量很大,如何在取件人到来时快速找出他想要的包裹就成了很重要的问题。

正巧,开菜鸟驿站前你是个程序员,于是很自然就想到可以把包裹按照收件人的手机尾号进行堆放。只要以倒数第二位作为货架号、倒数第一位作为层号就可以了。比如手机尾号 24 的取件人的包裹就应该放在二号货架的第四层。

你家的菜鸟驿站开张了,生意很好,货架也够用。双十一期间虽然包裹多、货架上放不下,但问题不大,货架上放不下就堆在对应货架前的地上:二号货架第四层找不到包裹,就在二号货架前地上的包裹堆里找就可以了。特殊时期特殊对待,大家都是街坊,可以理解。

隔壁吴老二从小和你不对付,听说你赚了钱就气得浑身发抖。他摸清楚你是按照手机尾号放快递之后就想了个法子,特意去营业厅挑了一堆以 2X 结尾的手机号,每天从淘宝上买些不值钱又占地方的玩意儿寄到菜鸟驿站。于是二号货架常年是满的,货架前也常年堆着一堆包裹。别人的包裹都很快可以找到,耗费不到一分钟;而凡是手机尾号是 2X 的居民就都倒了血霉了,货架上基本没法找到,得去快件堆里一个个翻,每次不花个五六分钟别想找到包裹。这要是店里人手不够,尾号非 2X 的人还排队排在几个 2X 尾号的人后面取件,那酸爽……反正从此以后,吐槽源源不断,你的生意也一天不如一天了。

小区里有个产品经理朋友建议你可以多加个货架专门处理二号货架爆仓的情况,但你清楚地知道这样的特殊处理是治标不治本的。问题的根本是只要有人知道你是按照手机尾号放置包裹的,就可以用很小的成本「构造」包裹,让特定手机尾号的包裹像洪水般涌来(嗯,此处点题),降低你店里的工作效率,达到攻击的目的。

所以解决方法也就很明显了:不要让取件人可以轻易猜到你是如何放置包裹的。

在苦思冥想一周无果之后,你打听了一下,才发现隔壁村的菜鸟驿站居然是用现成的管理系统的。包裹入站时系统直接生成取件码,取件码均匀分散到货架层数,比如 1-2-1234 表示这是本驿站收到的第 1234 个包裹,应该放在一号货架第二层。这样取件人就没法通过构造特定的包裹进行攻击了。

你恍然大悟,然后把手边的《编程珠玑》给扔了。(啊抱歉,忽然发现上面的想法好像不是这本书里来的,但一时半会儿想不出是哪本书里提到的了。嘛~意思是这个意思,摊手。)

---

p.s. 这个问题原本问的是 Hash-Flooding,不幸中途被编辑上了「哈希碰撞攻击」的错误中文翻译,这是两个不同范围的概念。


user avatar   Gh0u1L5 网友的相关建议: 
      

如果一名程序员想要接触信息安全的话,哈希洪水攻击我是一定会重点圈出来的。一方面是因为它的原理非常简单,只要掌握一点数据结构方面的基本知识就能理解;另一方面是因为,它是我入坑以来对我启发最大的技术之一,从中不仅可以学到一项具体的攻击技术,还可以看到“软件开发从业人员”和“信息安全从业人员”之间决定性的分野。

比较遗憾的是,国内互联网上真正搞懂这项攻击的人不多。虽然有几篇不错的文章讲清了它的攻击原理,但他们给出的防御手段也不过是“限制参数个数”、“禁止不明用户提交数据”之类的东西,无法从根本上解决哈希洪水攻击。所以我才决定这几天抽时间写篇长文回答,讲讲哈希洪水攻击的攻与防。

顺便一提,我没记错的话,阿里还曾经拿这个问题做过面试题,这个选题可以说是很有品味了。


0x01 哈希洪水攻击的成因

哈希洪水攻击(Hash-Flooding Attack)是一种拒绝服务攻击(Denial of Service),一旦后端接口存在合适的攻击面,攻击者就能轻松让整台服务器陷入瘫痪。

那么,所谓的“合适的攻击面”到底指什么呢?我们先来复习一下本科水平的数据结构知识吧。

在各种常用的数据结构里,有些数据结构的“平均运行时间”和“最差运行时间”会差很远,比如哈希表(Hash Table)。假设我们想要连续插入 个元素到哈希表中:

  • 如果这些元素的键(Key)极少出现相同哈希值,这项任务就只需 的时间。
  • 如果这些键频繁出现相同的哈希值(频繁发生碰撞),这项任务就需要 的时间。

这应该是每个学过数据结构的学生都知道的常识,不过大部分人看过之后就很快忘掉了。

2003年,Scott A. Crosby 和 Dan S. Wallach 两位研究人员发表了一篇论文:Denial of Service via Algorithmic Complexity Attacks。在这篇论文里他们首次提出:既然有些数据结构的最差运行时间这么废物,我们有没有可能通过算法上的漏洞,强行构造出一个最差情况,让服务器把全部的资源都浪费在处理这个最差情况上?

例如,Java自带的字符串哈希函数,使用的是“DJBX33A算法”的变种,这个算法是这样定义的:

而根据这个算法定义,我们就可以轻松地构造出一批具有一样哈希值的字符串:

这样一来,只要构造出几万个同样哈希的字符串,把它们提交给服务器做哈希表, 就能用很低的成本将服务器打瘫了。

这个成本具体有多低呢?依2011年的实验数据,攻击一台基于Java(Tomcat)的服务器时,仅仅需要6KB/s的流量就能打瘫一颗 Intel i7 处理器,1GB/s的流量可以打瘫 100000 颗 Intel i7 处理器,性价比远超TCP半开连接等传统的拒绝服务攻击。


0x02 哈希洪水攻击的防御

搞清原理之后,很多人第一时间想到的防御手段应该是:“限制参数个数”、“禁止不明用户提交数据”这类吧?是,这类方案理论上是可行的,起码在项目规模不大的时候没什么问题。

然而随着项目的不断演进,项目人员的入职离职,整个项目的数据接口会逐渐脱离掌控。你固然可以通过一些全局配置(比如PHP的max_input_vars)来限制参数个数,但其他团队的程序员却可能在不知情的情况下,为了“绕过那个搞网络安全的哥们设的神经病限制”,而故意选择用 JSON 等方式提交大量数据,给整个系统深深地埋下一颗地雷。

因此,为了根绝隐患,我们需要从更根本上避免攻击的发生。比如,我们能否找到更优秀的哈希算法,让那些键的哈希值完全不发生碰撞?

很遗憾,答案是不行,从数学角度上讲这根本不可能。因为一个哈希表的长度一般也就是几千个元素,根据生日悖论我们可以证明:不管你的算法设计得多么精妙,只要黑客掌握算法的所有细节,那就总能算出一组频繁碰撞的键来。

注意到我刚才那句话里隐藏的线索了吗?

如果黑客不能掌握算法的所有细节,是不是就不能算出一组频繁碰撞的键,也就没法发动哈希洪水攻击

换句话说,我们能不能在算法中加入一个黑客不知道的秘密参数?每建一张哈希表,我们就随机生成一个新的秘密参数。这样一来,即使是同样的内容,放在不同的表里也会产生完全不同的内存分配。这整个过程黑客完全无法预测,即使发生碰撞,也是小概率的巧合,而不是黑客在主动控制,攻击也就不可能成立了

这个黑客不知道的秘密参数,我们现在称之为哈希种子(Hash Seed)。而这类使用哈希种子的哈希算法,我们称之为带密钥哈希算法(Keyed Hash Function)

黑客一方的攻击目标,是想办法刺探出种子的值,或者在不知道种子的情况下构造出一组会碰撞的键来。而安全研究人员的目标,就是设计出更安全的带密钥哈希算法,保护好种子的安全,避免种子被黑客绕过。

这些年来,攻守双方在这个领域展开了激烈的攻防,来自Google、UIC等机构的众多研究人员设计了许多新的哈希函数:SipHash、MurmurHash、CityHash等等。这些算法不停地被推翻,不停地更新版本,到现在已经形成了一套稳定的算法标准,被众多编程语言和开源项目所采纳。

下面这张表来自SipHash官网,里面列举了众多采用SipHash-2-4算法的知名项目。其中Rust、Python、Ruby等语言更是把SipHash-2-4作为默认的哈希表实现方法,用这些语言编写的项目天生免疫哈希洪水攻击:

这些算法虽然在中文资料里名不见经传,很多人甚至可能是读到我这篇文章,才第一次听说这些算法的名字。但正是多亏了这些默默无名的算法,以及设计了这些算法的研究人员,我们才没有生活在一个“服务器三天一崩溃、五天一瘫痪”的世界里。


附注:在读了评论区知守的评论之后,补充一下Java提出的解决方案(JEP 180)。

从JDK 8开始,HashMap、LinkedHashMap和ConcurrentHashMap三个类引入了一套新的策略来处理哈希碰撞。

  • 当一个位置存储的元素个数小于8个时,仍然使用链表存储。
  • 当一个位置存储的元素个数大于等于8个时,改为使用平衡树来存储。

这样一来,就能保证最差的运行时间是 了。

为什么要设立“8个元素”(TREEIFY threshold)这样一个限制呢?因为平衡树相比链表而言有着更高的开销,以及更散乱的内存布局(影响缓存命中率)。在正常情况下,哈希表的一个位置大约只会存储1~4个左右的元素,所以没有必要专门开一个平衡树来存储冲突的元素,对一些性能敏感的应用来说会造成显著的负面影响。

实际应用中究竟选用平衡树还是SipHash,完全是一件见仁见智的事情,两边没有哪个有显著的优势,实现起来也都不是很困难。


0x03 后记

在本文开始的时候,我说过一句话:“它是我入坑以来对我启发最大的技术之一,从中不仅可以学到一项具体的攻击技术,还可以看到‘软件开发从业人员’和‘信息安全从业人员’之间决定性的分野”。

那么这项决定性的分野是什么呢?

我将它总结为一句话,并作为自己的座右铭:“Stay Malicious,保持恶意。”

“哈希表的最差时间复杂度是 ”——这是一项所有软件开发人员烂熟于心的基础知识,所有人都知道,但是所有人都只是看过一眼就忘在脑后了。直到2003年,才第一次有人提出可以用这个东西发动网络攻击,而且效果十分之出色。

在这个故事中,两位研究人员并没有掌握什么复杂深奥的神仙技术,仅仅只是用到一句本科水平的基础常识而已,可是深究下来却走出了这样一条别出心裁的攻击路径,为什么?因为他们懂得怎么样“怀着恶意”去应用手中的技术,这正是很多软件开发人员所欠缺的。而这一点点意识上的欠缺,将来也许就会变成一笔昂贵的学费砸在头上。

所以,Stay Malicious。

在一个充满恶意的虚拟世界,保持恶意才能让你走得更远。


觉得本文有价值的话,欢迎点个赞支持一下。对信息安全感兴趣的同学,也欢迎阅读我写的其他信息安全科普类文章:


user avatar   13641283343 网友的相关建议: 
      

举一个最简单的例子,在朝鲜战争中。

美国军很牛X,但是越过三八线,就会让我军打得连北都找不到;我军虽强,但是越过三八线大举深入,也会让美军打得一败涂地。

再举一个最简单例子,在抗日战争中。

日军很牛,但是越过湖南某线继续西进,就会让中国军队打得一败再败;中国军队虽然在这里可以不断取得胜利,但是继续深入追击日军,估计是看不到什么胜算的。


任何两个相邻的政权(或是长期交战的双方),战斗力的强弱,都会在某个边界发生逆转。

比如,曹魏、东吴政权之间,是以合肥一线为分界的。

曹魏大军敢大举越过这条线,通常都是以大败结束的。因为这意味着,曹魏进入了一个对自己不利,对东吴有利的地区打仗。

反过来说,东吴军队敢大举越过这条线,通常也是以失败结束的。因为这意味着,东吴进入了一个对自己不利,对曹魏有利的地区打仗。


总的来说,任何两个相邻国家的分界线(或是交战双方长期存在的分界线),并不是无缘无故出现的。

双方之所以会在那个地方分界,是因为甲方越过这条线,通常就会挨打;乙方越过这条线,通常也会挨打。所以双方都不敢轻易越过这条线。于是,双方就会达成某种默契,以这条线成为事实的分界线。


曹魏、蜀汉的分界线,也是因为类似的原因出现。

诸葛亮的北伐,从来都没有大举深入过曹魏境内,只是在这条分界线附近不断骚扰罢了。

如果有例外,就是诸葛亮第一次北伐,他因为出期不意,所以深入了曹魏境内。就算如此,诸葛亮也不敢大举逼近长安城。关键是,就算如此,最后也是以诸葛亮自贬三级结束。


只要我们知道这种最基本的军政知识,自然就会知道,诸葛亮北伐,曹魏不应战,并没有什么奇怪的。

因为诸葛亮的军事行动,一直停留在一个比较微妙的地方。这个地方,你说对诸葛亮完全有利吧,也实在未必,因为他已越过了长期博弈出来的分界线。

但是说一千道一万,诸葛亮显然不会真正远离这条分界线的,曹魏军队进入这个地方与诸葛亮作战,显然存在太多不确定的风险。

关键是,曹魏军队根本不用与诸葛亮打仗,只要耗一段时间,就可以让诸葛亮退军,并且夺回失去的地方。既然如此,曹魏军队为什么要与他作战呢?


这就好像我在分析刘备东征时的表现,刘备大呼小叫了半天,但是一直也不敢远离山区。表面上,这是刘备打得陆逊不敢应战,其实呢,刘备真有胆子,就直接顺流而下进入平原地区啊!

诸葛亮也是如此的,如果他真有心与曹魏作战,玩什么稳扎稳打呢,直接大举深入曹魏境内就可以了。


诸葛亮的想法很简单,那就是我想和你打仗,但是希望在一个对我有利的战场上、用对我有利的方式开战。

司马懿的想法也很简单,既然你想的仗,就得到一个对我有利的战场上,用我对我有利的方式开战。

既然双方谁也不愿意让这一步,自然无法进行战争了。


这不是谁怕谁的问题。战争的时机对自己有利,那就动如脱兔了;战争的时机对自己不利,那就要不动如山了。

作为一个将领,如果总纠结于,我不出战,别人会笑话我,别人会觉得我无能、我胆小。那他就不是一个合格的将领。因为一个优秀的将领,所考虑的问题永远是,现在出战的时机成熟吗?出战对我有利吗?至于别人会怎么看,那就叫扯淡!

======================

鉴于一些人的军事政治常识,所以补充一些答案。

任何交战双方,在进行到一定阶段,都会存在一条事实存在的分界线;任何相邻国家在博弈到一定阶段,都会存在一条事实存在的边境线。而且这种分界线、边境线为什么会存在呢?我在答案中以为,这就是常识,没有想到太多的都对此惊人的一无所知。

这种分界线的存在,取决于各种原因。

最常见的原因,自然是地理、地缘,比如某条大江、大河、大山,一方越过,就会丧失地理的屏障,一方越过就会进入险地。所以双方自然都会轻易越过。

再常见的就是后勤补给原因,你越向前推进,后勤补给压力就会越大;交战双方也好,相邻两国也好,通常都不能无限的向前推进,推进到某条线时,自然就会停止不再轻易向前了。

当然了,这只是客观原因,还有主观的因素,国力、军队素质。如果在这方面你非常强大,地理、地缘的困难,阻止不了你向前;如果你的军队素质非常强大,后勤的压力也阻止不了你,因为你的后勤可以从敌方那里获取。

但是不管怎么说,交战双方、相邻两国在特定的时间范畴内,都存在力量边缘的地方。魏强大,也不敢轻易越过秦岭;界牛X,也不敢深入关中;关键是,就算他们敢这样干,通常也得不偿失的;就算取得一点胜利,通常也是难以保住胜利果实的。

——————————

至于说,将领害怕别人笑话,所以出战,那只能证明他不合格。

有人反驳说,司马懿是非常优秀的将领,但是因为害怕别人笑话,于是就让两个将领出战,于是让诸葛亮打得溃不成军,损失惨重.........。按你这说法,司马懿肯定不是优秀的将领。

这逻辑,真让我无语了。司马懿是非常优秀的将领,并不是因为司马懿打过这种仗,如果司马懿就打过这种仗,我们只能说,他真不是合格的将领。

这就好像有人说诸葛亮知人善任,并不是因为诸葛亮重用过马谡。人们说曹操非常牛X,并不是因为他差一点被张绣杀死了。当然了,我们说司马懿是优秀的将领,也不是因为他因愤派军,被打得大败。

逻辑有两种。一种正常人的逻辑,一种是无良讼师的逻辑。

=======================

看到太多无聊、幼稚的人抬枉,就再补充一点。

魏蜀那条边境线,在诸葛亮执政前,就存在了;刘备不能向前突破;曹操无法突破;诸葛亮执政时期也一直存在,诸葛亮北伐若干次,也不能真正突破;诸葛亮死后,它依然存在了三十年。

事实证明,如此稳定的一条线,许多人非要无视。没有任何一条线,是可以永远存在的。但是一条能存在四五十年的线,无数当时的牛人试图突破,都只能徒劳无功,自有它存在的足够的道理。

如果这条线如此好突破,诸葛亮一再北伐无法突破,情何以堪啊?如果这条线如此好突破,诸葛亮死后,曹魏怎么还需要等三十多年才能突破?




  

相关话题

  如何评价「最大的安全公司之一 Norse Corp 濒临倒闭」? 
  要不要从信息安全转到会计? 
  如何看待近期媒体报道的「境外组织策反博士高级工程师」一案?涉密信息被泄漏到境外后果有多严重? 
  10 月 25 日韩国突发大面积断网,全国企业、普通家庭等均受影响,为何出现断网问题?将造成多大损失? 
  360 作了哪些恶? 
  网络软色情防不胜防,怎么做才能更好地保护青少年? 
  对一堆文件中的每一个文件单独加密,如果已知其中一些文件的明文和密文,是否会导致能推断出密钥? 
  MD5是32位的,也就是说理论上是有限的,而世界上的数据是无限的,那会不会生成重复的MD5值? 
  3个小时,用 C++ 写不出AVL树,有些迷茫,怎么办? 
  有哪些被骇客攻击的趣事? 

前一个讨论
有人找我做主播,想听听各位对主播行业的看法,是否建议入行?
下一个讨论
感觉现在男多女少,但相亲市场上大多数是女生,而且女生都会比男生主动,『主动提示』男主追她,是为什么?





© 2024-11-15 - tinynew.org. All Rights Reserved.
© 2024-11-15 - tinynew.org. 保留所有权利