In the previous article, I introduced the possibility of using Hash conflicts (collisions) to launch denial-of-service attacks against various languages (including PHP, Java, Ruby, and so on), but did not provide examples, after the article was published, @ Ferrari gave another article Supercolliding a PHP array. The article describes a PHP-based conflicting instance and the performance deterioration comparison. I will show you how to translate it.
Do you know that it takes more than 30 seconds to insert 65536 elements with constructed key values into the PHP array? In general, this process takes only 0.1 seconds ..
See the following example:
<?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 'insert', $ size, 'malicious element require ', $ endTime-$ startTime, 'second', "\ n ";
-
- $ StartTime = microtime (true );
- $ Array = array ();
- For ($ key = 0, $ maxKey = $ size-1; $ key <= $ maxKey; ++ $ key ){
- $ Array [$ key] = 0;
- }
- $ EndTime = microtime (true );
- Echo 'insert', $ size, 'normal element require ', $ endTime-$ startTime, 'second', "\ n ";
In the above example, the execution result on my machine is as follows:
It takes 65536 seconds to insert 43.1438360214 malicious elements
- 65536 is required for inserting 0.0210378170013 common elements
Is the difference exaggerated ?!
As I mentioned in the previous article, after specially constructed key values, every insert of PHP will cause Hash conflicts, resulting in the degradation of the underlying Hash table of array in PHP into a linked list:
Hash collision
In this way, PHP needs to traverse this linked list every time it is inserted. As you can imagine, the first insertion requires traversing 0 elements, the second is 1, and the third is 3, 65,536th is 65535, so a total of 65534*65535/2 = 2147385345 traversal ....
How is the key value constructed?
In PHP, if the key value is a number, the Hash value is the number itself. Generally, index & tableMask. tableMask is used to ensure that the numeric index does not exceed the number of elements allowed by the array, that is, the number of Arrays-1.
The Hashtable size of PHP is an exponential value of 2. For example, if you store an array of 10 elements, the actual size of the array is 16. If you store 20 elements, the actual size is 32, the actual size of 63 words is 64. when the number of elements you store is greater than the current maximum number of elements in the array, PHP will resize the array and re-Hash it.
Now let's assume that we want to store 64 elements (the middle may be resized, but we only need to know that the final array size is 64 and the corresponding tableMask is 63: 0111111 ), if the key value of the element we saved for the first time is 0, then the hash value is 0, the second time we saved 64, and the hash (1000000 & 0111111) value is 0, we use 128 for the third time, and 192 for the fourth time... The underlying PHP array can be used to Hash all elements to bucket 0, which degrades the Hash table to a linked list.
Of course, if the key value is a string, it will be a little more troublesome, but the PHP Hash algorithm is open-source and known, so you can do it with your heart.
Address: http://www.laruence.com/2011/12/30/2435.html
Article