探秘PHP拒绝服务攻击

你可以自己模拟一下简单的攻击,以更加了解如何才能更安全。

它是怎么起作用的

在通常的情况下,哈希表被优化的速度非常快。但如果有人将互相冲突的键值插入,性能就会突然变得很糟糕。

 

如果哈希表使用开放的地址来实现,一个冲突的键值会针对链接列表中的所有元素做出检查。如果你插入了n个元素,为了公平性你就得检查 1+2+3+..+(n-1) 个元素(复杂度为O(n²))。

 

 

如果你想早知道更多关于这个在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 --X POST \

-"Accept: application/json" \

-"Content-type: application/json" \

-'{"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并没有使用内部的哈希图。

我确定还有很多用户数据和哈希表一起被调用的其他种情况。

自己尝试一下

我把测试脚本和样例页面放在github库里了,甚至还增加了上千个自冲突键值。