所有主流语言中都存在的重大的复杂攻击漏洞。PHP在处理表单时有漏洞,但现在每个Web程序都在使用JSON API,仍然很容易受到复杂的攻击。
它是怎么起作用的
在通常的情况下,哈希表被优化的速度非常快。但如果有人将互相冲突的键值插入,性能就会突然变得很糟糕。
如果哈希表使用开放的地址来实现,一个冲突的键值会针对链接列表中的所有元素做出检查。如果你插入了n个元素,为了公平性你就得检查 1+2+3+..+(n-1) 个元素(复杂度为O(n2))。
如果你想早知道更多关于这个在PHP里是怎么起作用的,你还可以读读这篇信息量比较丰富的文章。
使用POST数据作为攻击
为了方便访问,PHP把所有的POST字段都存放在$POST图里。
<!--?php echo $_POST ["param"]; ?-->
下面的POST请求是针对上卖弄的PHP页面的,会导致5个键值冲。如果你发送了2^16个键值,这时的计算量就相当于要让i7处理器忙上30秒钟。
curl--data"4vq=key1&4wP2=key2&5Uq=key3&5VP=key4&64q=key5"http://localhost:8080/index.php
尽管在一些语言(比如Python)里哈希函数已经为了防止此类的攻击而做出了相应的修改,PHP通过在php.ini配置文件里简单地引入了一个max_input_vars指令解决了这个漏洞问题。
默认情况下,该指令被设置为1000,这意味着你在一个请求中不能发送超过1000个表单字段。1000个冲突不是真正的问题,因为它与正常情况下请求相比速度只慢了1/3.
使用JSON API作为攻击
由于Web已经进化到一个到处都是API的大网,我们可能已经忘记,在用户使用输入和数组的地方PHP仍然存在着哈希冲入漏洞攻击。
Web API通常支持JSON,因此使用标准PHP库的json_decode方法。这将默认解析所有在JSON文件里的键值到PHP图中,引起许多冲突。
下面是一个很简单的返回发送者姓名和邮件地址的API:
<!--?php header('Content-Type: application/json'); $body = file_get_contents('php://input'); $params = json_decode($body); $response = array('name' =--> $params->{'name'}, 'email' => $params->{'email'}); echo json_encode($response); ?>
如果我们把一个修改后的JSON请求发送给这个API,结果和POST参数会有一样的影响。
curl -v -X POST \ -H "Accept: application/json" \ -H "Content-type: application/json" \ -d '{"4vq":"key1", "4wP2":"key2", "5Uq":"key3", "5VP":"key4", "64q":"key5" }' \ http://example.com/api.php
测试
我将json_decode和导致一个可怕的二次函数的时间画了出来。在 2^16个键之后异常值出现了,原因是一个不同的哈希掩码,在当前阵列在数组增长超过 2^16个元素时,我们的冲突预计会引起16位哈希掩码的冲突。
如果把上面的JSON API样例托管在一个实际的服务器上,并且做出一些攻击,我们也会得到同样的结果。函数会达到平衡,因为Apache服务器处理每条请求的时间被限制在30秒以内。
我在AWS上跑了一个测试,其中有一个攻击者(蓝色)和一个受害者(黄色),并且为CPU占用率截了图。你能很容易就看明白,尽管攻击者除了发送POST请求外其他几乎什么事情都没有做,受害者为网页页面提供提供服务的性能还是会受到影响。
其他潜在的攻击载体
有趣的是,解析XML并没有使用内部的哈希图。
我确定还有很多用户数据和哈希表一起被调用的其他种情况