关于php Hash算法的一些整理总结
最近在公司内部的分享交流会上,有幸听到了鸟哥的关于php底层的一些算法的分享,虽然当时有些问题没有特别的明白,但是会后,查阅了各种各样的相关资料,对php的一些核心的hash算法有了进一步的理解和认识,下面就是总结下自己梳理的一些hash算法的点。
首先,大致的了解下php中的hash算法的应用,引用一些鸟哥博客中的话:
HashTable是php的核心,这话一点也不假。 PHP的Hash采用的是目前最为普遍的DJBX33A (Daniel J. Bernstein, Times 33 with Addition), 这个算法被广泛运用与多个软件项目,Apache, Perl和Berkeley DB等. 对于字符串而言这是目前所知道的最好的哈希算法,原因在于该算法的速度非常快,而且分类非常好(冲突小,分布均匀). 主要的核心思想是:
hash(i) = hash(i-1)*33 + str[i] 并且这个算法的初始值是5381,而其他的算法(apache的times算法以及perl的hash算法,初始值都是0),但为啥是这个值,鸟哥的说法是:
Magic Constant 5381:
1. odd number
2. prime number
3. deficient number
4. 001/010/100/000/101 b 对第3,4点理解还是不够透彻,希望可以在研究下。 至于说, 为什么是Times 33而不是Times 其他数字, 在PHP Hash算法的注释中也有一些说明, 希望对有兴趣的同学有用: DJBX33A (Daniel J. Bernstein, Times 33 with Addition) This is Daniel J. Bernstein's popular `times 33' hash function as
posted by him years ago on comp.lang.c. It basically uses a function
like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
known hash functions for strings. Because it is both computed very
fast and distributes very well. The magic of number 33, i.e. why it works better than many other
constants, prime or not, has never been adequately explained by
anyone. So I try an explanation: if one experimentally tests all
multipliers between 1 and 256 (as RSE did now) one detects that even
numbers are not useable at all. The remaining 128 odd numbers
(except for the number 1) work more or less all equally well. They
all distribute in an acceptable way and this way fill a hash table
with an average percent of approx. 86%. If one compares the Chi^2 values of the variants, the number 33 not
even has the best value. But the number 33 and a few other equally
good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
advantage to the remaining numbers in the large set of possible
multipliers: their multiply operation can be replaced by a faster
operation based on just one shift plus either a single addition
or subtraction operation. And because a hash function has to both
distribute good _and_ has to be very fast to compute, those few
numbers should be preferred and seems to be the reason why Daniel J.
Bernstein also preferred it. -- Ralf S. Engelschall <rse@engelschall.com>
其次,总结下什么情况下会出现hash的碰撞以及出现的原因:
因为php的数组以及各种对象类型底层都是转换成hash,来进行处理的,因此可以模拟数组的构造,来制造冲突的实例:
<?php
$size = pow(2, 16); $startTime = microtime(true);
$array = array();
for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) {
$array[$key] = 0;
}
$endTime = microtime(true);
echo '插入 ', $size, ' 个恶意的元素需要 ', $endTime - $startTime, ' 秒', "\n"; $startTime = microtime(true);
$array = array();
for ($key = 0, $maxKey = $size - 1; $key <= $maxKey; ++$key) {
$array[$key] = 0;
}
$endTime = microtime(true);
echo '插入 ', $size, ' 个普通元素需要 ', $endTime - $startTime, ' 秒', "\n";
最终的结果是:
插入 65536 个恶意的元素需要 43.1438360214 秒
插入 65536 个普通元素需要 0.0210378170013 秒
从上个例子中,可以看出,对数组的键值进行特殊的构造,使得php的每一次插入都造成了hash冲突,从而使php的array的hash迅速的退化成为链表。这就造成了hash的碰撞冲突。下面是鸟哥博客中的一个图片:

hash collison
那么, 这个键值是怎么构造的呢? 在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… 就可以使得底层的PHP数组把所有的元素都Hash到0号bucket上, 从而使得Hash表退化成链表了.
上述的这种情况就造成了hash 的碰撞冲突。那么黑客可以利用这些语言上的这个hash漏洞来进行构造出一些特别的键值对,对服务器进行攻击,导致服务器的带宽占满,服务器的cpu剧增,从而导致网站瘫痪。
那怎样,避免这种情况的发生,以及哪种语言版本是可以避免攻击的?
先说下php,php >= 5.3.9, >= 5.4.0RC4的版本是不受影响的,其余皆受影响。在不受影响的版本中,只是多增加了一个max_input_vars这个参数来进行防止的,简单的来说就是限制客户端post过来的数据,这是一种治标不治本的方法。
以上的都是一些自己从大牛博客上的一些总结,以及自己的一些理解!
关于php Hash算法的一些整理总结的更多相关文章
- 【整理】hash算法原理及常见函数
简介 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值. 散列表 ...
- 浅析nodeJS中的Crypto模块,包括hash算法,HMAC算法,加密算法知识,SSL协议
node.js的crypto在0.8版本,这个模块的主要功能是加密解密. node利用 OpenSSL库(https://www.openssl.org/source/)来实现它的加密技术, 这是因为 ...
- 逐步实现hash算法(基于BKDRhash函数)
哈希(Hash)算法,即散列函数.它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程.同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出.hash算法 ...
- Hash算法及java HashMap底层实现原理理解(含jdk 1.7以及jdk 1.8)
现在很多公司面试都喜欢问java的HashMap原理,特在此整理相关原理及实现,主要还是因为很多开发集合框架都不甚理解,更不要说各种其他数据结构了,所以造成面子造飞机,进去拧螺丝. 1.哈希表结构的优 ...
- 一致性HASH算法在分布式应用场景使用
其实不管redis还好,Mysql也好 这种数据存储介质,在分布式场景中都存在共同问题:即集群场景下服务路由.比如redis集群场景下,原本我们分3主3从部署.但万一有一天出现访问量暴增或其中一台机器 ...
- 编程艺术第十六~第二十章:全排列/跳台阶/奇偶调序,及一致性Hash算法
目录(?)[+] 第十六~第二十章:全排列,跳台阶,奇偶排序,第一个只出现一次等问题 作者:July.2011.10.16.出处:http://blog.csdn.net/v_JULY_v. 引言 ...
- 对一致性Hash算法,Java代码实现的深入研究
一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...
- 一致性hash算法详解
转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT) ...
- 一致性hash算法简介
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希 ...
随机推荐
- 从erase()谈起
面试中,因为我说自己熟悉C++,就问我一个问题,Vector<int>里, 想把元素为2的节点删除掉.该怎么做. 我已经很久没有用Vector了,但是只有硬着头皮想一下,第一个想起的是re ...
- 台球游戏的核心算法和AI(2)
前言: 最近研究了box2dweb, 觉得自己编写Html5版台球游戏的时机已然成熟. 这也算是圆自己的一个愿望, 一个梦想. 承接该序列的相关博文: • 台球游戏核心算法和AI(1) 同时结合htm ...
- ASP代码审计 -4.命令执行漏洞总结
命令执行漏洞: 保存为cmd.asp,提交链接: http://localhost/cmd.asp?ip=127.0.0.1 即可执行命令 <%ip=request("ip" ...
- Oracle、MySql、SQLServer 数据分页查询
最近简单的对oracle,mysql,sqlserver2005的数据分页查询作了研究,把各自的查询的语句贴出来供大家学习..... (一). mysql的分页查询 mysql的分页查询是最简单的,借 ...
- HTML DOM 实例-Document 对象
使用 document.write() 向输出流写文本 <html><body><script type="text/javascript">d ...
- java bean 转换工具
考量要素: 1.简单的约定优于配置的同名属性copy 2.嵌套属性copy 3.flattern(扁平化)支持,要支持N层结构的copy到一层结构. 4.性能 如下这个网页,里面提到了好多工具. ht ...
- Base64编码解码
一. Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就不能通过邮件传送.这样用途就受到了很大的 ...
- 禁用sqlserver的锁升级
锁升级 SQLSERVER.DB2中的锁是内存里面实现的,这就有个资源消耗问题,当锁的数量达到一个阀值或内存有压力时,就会引发锁升级.实际的情况是从row lock直接升级到table lock,而不 ...
- ASP.NET MVC Web API 学习笔记---第一个Web API程序
http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...
- js合并行
网上找了好久才找到,在这记录下. <script type="text/javascript" > function MergerRow(ID) { var tab = ...