面试宝典系列-Hash碰撞是什么?

为什么80%的码农都做不了架构师?>>>   hot3.png

哈希表(或散列表),是将键名key按指定的散列函数HASH经过HASH(key)计算后映射到表中一个记录,而这个数组就是哈希表。这里的HASH指任意的函数,例如MD5、CRC32、SHA1或你自定义的函数实现。

理想情况下HashTable的性能是O(1)的,性能消耗主要集中在散列函数HASH(key),通过HASH(key)直接定位到表中的记录。
而在实际情况下经常会发生key1 != key2,但HASH(key1) = HASH(key2),这种情况即Hash碰撞问题,碰撞的概率越低HashTable的性能越好。当然Hash算法太过复杂也会影响HashTable性能(HashTable碰撞)

PHP数组中,键名可以为数字或字符串类型。而在内核中只允许数字索引,对于字符串索引,内核采用了time33算法将字符串转换为整型(是对字符串的每个字符转换为ASCII码乘上33并且相加得到的结果)

键名为数字时:内核中哈希表的散列函数就是简单的h & ht->nTableMask,其中h代表PHP中设置的索引号,nTableMask等于哈希表分配的长度-1。

键名为字符串时:与数字索引相比,只是多了一步将字符串转换为整型。用到的算法是time33

HashTable碰撞:PHP中使用一个叫Backet的结构体表示桶,同一哈希值的所有桶被组织为一个单链表。(先根据哈希值找到位置,然后再判断原始key是否相同,如果不相同,找单链表下一个元素)

PHP哈希表最小容量是8(2^3),最大容量是0×80000000(2^31),并向2的整数次幂圆整(即长度会自动扩展为2的整数次幂,如13个元素的哈希表长度为16;100个元素的哈希表长度为128)

防hashTable碰撞攻击(构造一个大数组,键值产生的哈希值都相同,然后post提交这个数组)在>=PHP5.3.9的版本中增加了一个配置项max_input_vars,用于标识一次http请求最大接收的参数个数,默认为1000。但如果是json方式提交,并不能防止攻击。

一般来说有两种方式,一是限制每个桶链表的最长长度;二是使用其它数据结构如红黑树取代链表组织碰撞哈希(并不解决哈希碰撞,只是减轻攻击影响,将N个数据的操作时间从O(N^2)降至O(NlogN),代价是普通情况下接近O(1)的操作均变为O(logN))

转载于:https://my.oschina.net/suyain/blog/1858745

你可能感兴趣的:(面试宝典系列-Hash碰撞是什么?)