最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

哈希表之殇

  • 2012-02-16
  • 本文字数:2760 字

    阅读完需:约 9 分钟

2011 年 12 月 28 日,由 Google 赞助成立的安全漏洞研究组织 oCERT(Open source Computer Emergency Response Team — 开源软件应急响应团队)公开了一份安全漏洞报告。这份报告是几个月前由德国安全研究公司 nrun.com 所提供的,其核心内容是:目前绝大多数的 web 应用,都存在着一个叫做哈希碰撞式拒绝服务攻击的漏洞(Hash Collision DoS)。这份报告的公布,使得 2011 年剩下的几天里,各互联网公司的技术团队集体忙于对网站进行针对此漏洞的防护工作。硝烟散尽之后,让我们一起从攻击者的角度重新审视一下这个漏洞及其利用手法。

如果你熟悉几种常用语言下的哈希表(HashTable)实现,你大概会清楚以下的一些关于哈希表的基本概念:

  1. 哈希表通过一个哈希函数对键值(key)进行散列操作,并且最终根据散列结果将键值对(key-value-pair)储存到数组的某个节点(一般通过对数组长度取余实现)。
  2. 哈希表的数组长度会根据元素的实际数量动态进行扩容,以保证有足够空间并降低取余后的结果出现重复的可能性。不同的实现,其初始默认长度、扩容条件及扩容算法均可能有所区别。

极端情况下,哈希表将会退化成链表。根据上面的基础知识,我们知道这里的极端情况包括两种:所有元素的哈希值相等;或者所有元素的哈希值针对哈希表数组长度取余的结果相等。而退化为链表则会导致哈希表性能的急剧下降。实际测试中,针对 8 万条级别的数据,原本只需要数毫秒即可完成的插入或者查询操作,在退化为链表后则需要长达 30 秒以上的时间才能完成。

那么对攻击者来说,利用这一原理对某个 web 站点发起拒绝服务攻击只需要考虑以下两个问题:

  • 问题一、如何构造一个可使哈希表完全退化成链表的键值集合。
  • 问题二、如何使用该集合引导目标服务器建立一个哈希表数据结构。

针对问题一,具体的思路很简单,就是要找到一个字符串集合,使得该集合的每个元素要么满足哈希值相等;要么使得其哈希值针对哈希表数组长度取余的结果相等。构造大量的哈希冲突是一个比较困难的问题。但是对攻击者来说,非常幸运的是目前常见的哈希表的哈希函数实现,都是基于著名的 DJBX33 哈希算法或者其变形算法。比如,PHP5 使用的是 DJBX33A;ASP.NET 和 Python 使用的是 DJBX33X;Java 使用的是一个做了两个常数变形的变种 DJBX33A。针对这些哈希算法,攻击者已经可以有很多方法做针对性的哈希碰撞生成了。最常用的方法有“相等子串法”和“中间相遇法”等。以“相等子串法”为例,由于 DJBX33A 系列哈希算法满足一个很有意思的特性:如果 hash(“string1”) = hash(“string2”),那么在相同位置包含此 2 个子串的父串哈希结果将会产生碰撞,既:hash(“prefix_string1_postfix”) = hash(“prefix_string2_postfix”)。根据这一特性,攻击者如果能找到最简单的两个碰撞字符串,那么就可以很快通过反复组合,生成 2 的 n 次方个长度为 2n 的碰撞字符串。“中间相遇法”事实上是一种暴力破解办法。只不过通过巧妙删选缩小了结果集的甄别范围,然后在可能产生碰撞的结果集中遍历寻找碰撞集合。除此之外,针对较为复杂的哈希算法的碰撞,如 MD5 等算法,我国的王小云教授的“模差分法”是一种比较实用的碰撞分析方法。

如果通过算法构造哈希结果完全一致的字符串集合有难度,那么也可以退而求其次,只要满足哈希值对哈希表数组长度取余的最终结果相等就可以了。网上目前有很多针对 PHP 的示例攻击代码,就是根据这个原理实现的。利用这种方式,需要对该语言下哈希表数组经过反复扩容后的最终长度如何产生有一个清楚的了解。例如在 PHP 的实现中,所有哈希表数组的长度一定是 2 的 n 次方。根据元素总个数和加载因子(一个哈希表实现中满足扩容条件的临界值),就可以计算出最终生成的哈希表的数组长度。剩下的事情就只需要保证待选键值的哈希结果对这个长度取余的结果相等,这样即可达到制造大量哈希冲突字符串的目的。

在成功构造好一个可以使哈希表完全退化成链表的键值集合后,攻击者需要来解决第二个问题:如何使用该集合在服务器端建立一个哈希表数据结构。

这个问题事实上已经再简单不过了:在所有的 web 应用中,为了方便程序对 web 请求的各项参数进行快速读操作,HTTP Request 中的 Header, Form 以及 QueryString,都使用了哈希表进行存储。那么剩下的工作很简单:就是以我们精心构造好的键值列表作为一次 HTTP 请求的 Header,Form 或者 QueryString 就可以了。实际攻击中,由于大量 Form 表单的 Post 构造更加简单,甚至可以使用浏览器完成,所以也会通常成为进行攻击的首选突破口。通过在单机上重复构造大量的 HTTP Post 请求,向 Web 服务器发送大量表单数据,会使得目标服务器的 CPU 迅速被占满而失去服务能力,达到攻击目的。

如果对方的服务器数量比较多,或者防火墙敏锐地发现了攻击者短时间内向服务器 Post 大量数据的行为,并进行了阻截,那么有可能还是达不到让对方“拒绝服务”的目的。这种情况下,攻击者会倾向于使用一定数量的“僵尸网络”对目标发起攻击。由于这个攻击非常简单,只需要构造一个 HTTP 请求即可实现,那么你可以去自己创建一个内容非常吸引人的页面,或者利用一个访问量较大但是存在跨站脚本漏洞(XSS)的页面,在页面中加入一小段对最终用户不可见,但是会自动发送一个 Post 请求到目标站点的 JavaScript 脚本,你的拒绝服务攻击(DoS)就成功升级为分布式拒绝服务攻击(DDoS)了。而访问这些页面的普通用户,则会在不知情的情况下成为帮助你继续攻击的“僵尸”群。

文章的最后,还是想补充一下关于针对这类攻击的防护工作。目前绝大部分的补丁都是针对 HTTP 请求中表单项的数量加以限制。这个方法确实有效。测试数据显示,1000 个元素的链表操作对性能的影响还是可以接受的。但是如果你的 Web 应用在服务端需要接收某个表单项,并通过字符处理(不管是 XML 还是 JSON)将用户输入的表单值转换成哈希表的话,那么很遗憾,目前这些补丁都帮不了你,你的应用将依然存在被拒绝服务攻击的可能。只不过攻击的方式从构造 HTTP Request 中的哈希表,变成了构造实际业务处理代码中的哈希表。对这一问题的完美解决方案,应该是如 Perl 在 n 年前做的那样:在哈希算法中引入随机盐使得构造哈希冲突变为不可能。

参考文章

关于作者

殷钧钧( Joey Yin ),Web 开发者,某外企企业架构师。业余时间,他是一名白帽子,独立安全组织 OWASP 成员。主要关注的技术领域有应用安全、分布式系统架构、以及程序员的敏捷实践。个人博客: http://unclejoey.com


感谢郑柯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-02-16 00:007726

评论

发布
暂无评论
发现更多内容

从零开始学习3D可视化之物体选择

ThingJS数字孪生引擎

大前端 可视化 程序媛 3D可视化 数字孪生

双非渣硕,开发两年,苦刷算法47天,四面字节斩获offer

Java 程序员 架构 面试 算法

从渗透测试小白到网络安全大佬的成长之路

学神来啦

Linux 运维 网络安全 渗透测试

鉴释×CSDN丨国内外操作系统生态差异在哪?

鉴释

操作系统

Java的函数式接口

中原银行

Java 函数式接口 中原银行

产业互联网时代的数字化转型与创新

CECBC

Redis入门五:主从复制

打工人!

redis 主从复制 6月日更

架构实战营 - 模块 6- 作业

carl

🌏【架构师指南】分布式技术知识点总结(中)

洛神灬殇

分布式架构 架构师技能 分布式技术 6月日更

“半监督”、“自监督”怎么用?| 算法深度剖析与实战分享

网易易盾技术团队

AI 算法 算法实践 实践案例 深度半监督

浅谈B端产品的表单元素设计

LigaAI

产品经理 UI 产品设计与思考

ES6 迭代器简述

编程三昧

JavaScript 大前端 ES6 迭代器

网络抓包实战04——深入浅出连接建立

青春不可负,生活不可欺

信息安全与网络安全的关系

网络安全学海

程序员 网络安全 安全 信息安全 渗透测试

值得收藏的15个JavaScript语句

devpoint

JavaScript array 6月日更

冷门科普类自媒体如何才能脱颖而出

石头IT视角

英特尔宋继强:异构计算的关键一环,先进封装已经走向前台

E科讯

搭建企业私有GIT服务

IT视界

git

dubbogo 社区负责人于雨说

apache/dubbo-go

dubbo dubbo-go dubbogo

指挥中心情指勤一体化解决方案,河北公安情指勤一体化建设

新华三商用终端新品全系入市,重塑办公极致体验

科技热闻

接口全面重构TypeScript ,让uni-app 具备出色的基础音视频能力

ZEGO即构

typescript uni-app 音视频

强化学习 | COMA

行者AI

人工智能

网络抓包实战05——深入浅出连接关闭

青春不可负,生活不可欺

联邦学习—金融数据壁垒和隐私保护的解决之道

索信达控股

大数据 金融科技 联邦学习 金融 数据隐私

虚拟货币监管再加码:央行约谈部分金融机构 要求切断支付链路

CECBC

5分钟速读之Rust权威指南(二十八)RefCell<T>

wzx

rust

区块链如何赋能智慧城市

CECBC

算法有救了!GitHub上神仙项目手把手带你刷算法,Star数已破110k

Java架构师迁哥

网络抓包实战03——TCP/IP协议栈:数据包如何穿越各层协议

青春不可负,生活不可欺

微服务到底是什么?spring cloud在国内中小型公司能用起来吗?

Java架构师迁哥

哈希表之殇_安全_殷钧钧_InfoQ精选文章