最近在公司内部的分享交流会上,有幸听到了鸟哥的关于php底层的一些算法的分享,虽然当时有些问题没有特别的明白,但是会后,查阅了各种各样的相关资料,对php的一些核心的hash算法有了进一步的理解和认识,下面就是总结下自己梳理的一些hash算法的点。

  首先,大致的了解下php中的hash算法的应用,引用一些鸟哥博客中的话:

  1. HashTablephp的核心,这话一点也不假。
  2.  
  3. PHPHash采用的是目前最为普遍的DJBX33A (Daniel J. Bernstein, Times 33 with Addition), 这个算法被广泛运用与多个软件项目,Apache, PerlBerkeley DB等. 对于字符串而言这是目前所知道的最好的哈希算法,原因在于该算法的速度非常快,而且分类非常好(冲突小,分布均匀).
  4.  
  5. 主要的核心思想是:
  6. hash(i) = hash(i-1)*33 + str[i]
  7.  
  8. 并且这个算法的初始值是5381,而其他的算法(apachetimes算法以及perlhash算法,初始值都是0),但为啥是这个值,鸟哥的说法是:
  9. Magic Constant 5381:
  10. 1. odd number
  11. 2. prime number
  12. 3. deficient number
  13. 4. 001/010/100/000/101 b
  14.  
  15. 对第3,4点理解还是不够透彻,希望可以在研究下。
  16.  
  17. 至于说, 为什么是Times 33而不是Times 其他数字, PHP Hash算法的注释中也有一些说明, 希望对有兴趣的同学有用:
  18.  
  19. DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
  20.  
  21. This is Daniel J. Bernstein's popular `times 33' hash function as
  22. posted by him years ago on comp.lang.c. It basically uses a function
  23. like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
  24. known hash functions for strings. Because it is both computed very
  25. fast and distributes very well.
  26.  
  27. The magic of number 33, i.e. why it works better than many other
  28. constants, prime or not, has never been adequately explained by
  29. anyone. So I try an explanation: if one experimentally tests all
  30. multipliers between 1 and 256 (as RSE did now) one detects that even
  31. numbers are not useable at all. The remaining 128 odd numbers
  32. (except for the number 1) work more or less all equally well. They
  33. all distribute in an acceptable way and this way fill a hash table
  34. with an average percent of approx. 86%.
  35.  
  36. If one compares the Chi^2 values of the variants, the number 33 not
  37. even has the best value. But the number 33 and a few other equally
  38. good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
  39. advantage to the remaining numbers in the large set of possible
  40. multipliers: their multiply operation can be replaced by a faster
  41. operation based on just one shift plus either a single addition
  42. or subtraction operation. And because a hash function has to both
  43. distribute good _and_ has to be very fast to compute, those few
  44. numbers should be preferred and seems to be the reason why Daniel J.
  45. Bernstein also preferred it.
  46.  
  47. -- Ralf S. Engelschall <rse@engelschall.com>

  其次,总结下什么情况下会出现hash的碰撞以及出现的原因:

  因为php的数组以及各种对象类型底层都是转换成hash,来进行处理的,因此可以模拟数组的构造,来制造冲突的实例:

  1. <?php
  2. $size = pow(2, 16);
  3.  
  4. $startTime = microtime(true);
  5. $array = array();
  6. for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) {
  7. $array[$key] = 0;
  8. }
  9. $endTime = microtime(true);
  10. echo '插入 ', $size, ' 个恶意的元素需要 ', $endTime - $startTime, ' 秒', "\n";
  11.  
  12. $startTime = microtime(true);
  13. $array = array();
  14. for ($key = 0, $maxKey = $size - 1; $key <= $maxKey; ++$key) {
  15. $array[$key] = 0;
  16. }
  17. $endTime = microtime(true);
  18. echo '插入 ', $size, ' 个普通元素需要 ', $endTime - $startTime, ' 秒', "\n";

最终的结果是:

  1. 插入 65536 个恶意的元素需要 43.1438360214
  2. 插入 65536 个普通元素需要 0.0210378170013

从上个例子中,可以看出,对数组的键值进行特殊的构造,使得php的每一次插入都造成了hash冲突,从而使php的array的hash迅速的退化成为链表。这就造成了hash的碰撞冲突。下面是鸟哥博客中的一个图片:

                  hash collison

  1. 那么, 这个键值是怎么构造的呢?
  2.  
  3. PHP中,如果键值是数字, 那么Hash的时候就是数字本身, 一般的时候都是, index & tableMask. tableMask是用来保证数字索引不会超出数组可容纳的元素个数值, 也就是数组个数-1.
  4.  
  5. PHPHashtable的大小都是2的指数, 比如如果你存入10个元素的数组, 那么数组实际大小是16, 如果存入20个, 则实际大小为32, 63个话, 实际大小为64. 当你的存入的元素个数大于了数组目前的最多元素个数的时候, PHP会对这个数组进行扩容, 并且从新Hash.
  6.  
  7. 现在, 我们假设要存入64个元素(中间可能会经过扩容, 但是我们只需要知道, 最后的数组大小是64, 并且对应的tableMask63:0111111), 那么如果第一次我们存入的元素的键值为0, hash后的值为0, 第二次我们存入64, hash(1000000 & 0111111)的值也为0, 第三次我们用128, 第四次用192 就可以使得底层的PHP数组把所有的元素都Hash0bucket上, 从而使得Hash表退化成链表了.

上述的这种情况就造成了hash 的碰撞冲突。那么黑客可以利用这些语言上的这个hash漏洞来进行构造出一些特别的键值对,对服务器进行攻击,导致服务器的带宽占满,服务器的cpu剧增,从而导致网站瘫痪。

那怎样,避免这种情况的发生,以及哪种语言版本是可以避免攻击的?

  先说下php,php >= 5.3.9, >= 5.4.0RC4的版本是不受影响的,其余皆受影响。在不受影响的版本中,只是多增加了一个max_input_vars这个参数来进行防止的,简单的来说就是限制客户端post过来的数据,这是一种治标不治本的方法。

  以上的都是一些自己从大牛博客上的一些总结,以及自己的一些理解!

关于php Hash算法的一些整理总结的更多相关文章

  1. 【整理】hash算法原理及常见函数

    简介 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.        散列表 ...

  2. 浅析nodeJS中的Crypto模块,包括hash算法,HMAC算法,加密算法知识,SSL协议

    node.js的crypto在0.8版本,这个模块的主要功能是加密解密. node利用 OpenSSL库(https://www.openssl.org/source/)来实现它的加密技术, 这是因为 ...

  3. 逐步实现hash算法(基于BKDRhash函数)

    哈希(Hash)算法,即散列函数.它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程.同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出.hash算法 ...

  4. Hash算法及java HashMap底层实现原理理解(含jdk 1.7以及jdk 1.8)

    现在很多公司面试都喜欢问java的HashMap原理,特在此整理相关原理及实现,主要还是因为很多开发集合框架都不甚理解,更不要说各种其他数据结构了,所以造成面子造飞机,进去拧螺丝. 1.哈希表结构的优 ...

  5. 一致性HASH算法在分布式应用场景使用

    其实不管redis还好,Mysql也好 这种数据存储介质,在分布式场景中都存在共同问题:即集群场景下服务路由.比如redis集群场景下,原本我们分3主3从部署.但万一有一天出现访问量暴增或其中一台机器 ...

  6. 编程艺术第十六~第二十章:全排列/跳台阶/奇偶调序,及一致性Hash算法

    目录(?)[+]   第十六~第二十章:全排列,跳台阶,奇偶排序,第一个只出现一次等问题 作者:July.2011.10.16.出处:http://blog.csdn.net/v_JULY_v. 引言 ...

  7. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  8. 一致性hash算法详解

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179     一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT) ...

  9. 一致性hash算法简介

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希 ...

随机推荐

  1. html之小积累-.-iframe自适应高度

    在做系统框架的时候,常常会用到iframe,当需求是iframe不能出现纵向滚动条,需要根据加载页面的高度,一致延伸,但是iframe的高度自适应问题比较麻烦,当时也是纠结了好久. 方案1:当遇到if ...

  2. Insert Interval

    在已经排好序的区间中,插入一个新的区间,与merge的做法类似 Given a set of non-overlapping intervals, insert a new interval into ...

  3. C++模板中的函数对象

    在C++模板类map中一个参数为Compare类型,该类型为一个比较函数,其完整定义如下: template< class Key, class T, class Compare = std:: ...

  4. jdbc 配置

    jdbc 配置 Class.forName("com.mysql.jdbc.Driver")  ;//加载数据库驱动 Connection conn=null; String ur ...

  5. 如何判断一条sql(update,delete)语句是否执行成功

    如何判断一条sql(update,delete)语句是否执行成功 catch  (SQLException    e)  {  }  catch不到错误应该就成功了.   ============== ...

  6. ES(一): 架构及原理

    Elasticsearch 是一个兼有搜索引擎和NoSQL数据库功能的开源系统,基于Java/Lucene构建,可以用于全文搜索,结构化搜索以及近实时分析.可以说Lucene是当今最先进,最高效的全功 ...

  7. HA(High available)-Keepalived高可用性集群(双机热备)单点实验-菜鸟入门级

    HA(High available)-Keepalived高可用性集群   Keepalived 是一个基于VRRP虚拟路由冗余协议来实现的WEB 服务高可用方案,虚拟路由冗余协议 (Virtual ...

  8. 【MySQL】结构行长度的一些限制

    今天被开发提交的DDL变更再次困惑,表中字段较多,希望将已有的两个varchar(4000)字段改为varchar(20000),我想innodb对varchar的存储不就是取前768字节记录当前行空 ...

  9. Asp.net MVC 之过滤器

    整理一下MVC中的几种过滤器,以及每种过滤器是干什么用的 四种过滤器 1.AuthorizationFilter(授权过滤器) 2.ActionFilter(方法过滤器) 3.ResultFilter ...

  10. java程序打包成jar文件,使用到第三方jar包

    1.右击工程选择Export—>选择JAR file—>选择NEXT,如下图所示 2.选择需要打包的工程,并且选择存放目录,我这放在 E:\jartest 目录下,然后点击NEXT,如下图 ...