自从我开通这个博客几个月后,流量就空前高涨。我写了一篇文章,分别投在 Hacker News 和 Reddit 都 “爆红”了。
它一登上内容头条,我的小服务器就要彻底崩溃了。请求像海啸一样涌入,Apache 苦苦挣扎,我只能无助地坐着,一遍又一遍地重启机器——就像消防员用水枪灭火一样。
这要拿互联网术语来说,这叫做“死亡拥抱”,挺吓人的。
当时,我很难形容当时收到的请求有多么密集,以及给我带来的压力有多大。
就在今年二月,我又写了一篇帖子,几分钟内就登上了 Hacker News 的榜单第一名。这一回,我可做好了充分的准备。我先保存了一份服务器日志,然后制作了一个可视化图表,准确展现我每月 6 美元的小服务器究竟经历了什么。
服务器的每个 Web 请求都用一个向服务器移动的圆圈表示。查看右下角的图例:
-机器人 vs. 真实用户:基于用户代理检测。合法机器人的名称中通常包含“bot”,而其他机器人则通过启发式识别。
-响应类型如下:
- ✅ 200 OK:请求成功
- 🔄重定向:表示为摆动的点
- ❌ 404 Not Found:屏幕上掉落的红点
- 💥 Zip 炸弹:稍后向各位详细介绍
我的博客运行在一个自定义PHP框架上。大多数页面都缓存在memcached中,因此每个页面每小时仅查询一次数据库。这种高效的配置在过去曾处理过数百万次请求,包括我关于被机器学习解雇和登上 BBC 的热门故事。
制造ZIP炸弹方法之一
网络上的大部分流量来自机器人。这些机器人大多用于发现新内容。例如 RSS 订阅阅读器、抓取内容的搜索引擎,或者如今为 LLM 提供内容支持的人工智能机器人。
但也存在不少恶意机器人。这些机器人来自垃圾邮件发送者、内容抓取者或黑客。在我的前雇主那里,一个机器人发现了 WordPress 的一个漏洞,并在我们的服务器中插入了一个恶意脚本。然后,它将服务器变成了一个用于 DDOS 攻击的僵尸网络。我的早期网站之一就因为机器人生成垃圾邮件而完全从谷歌搜索结果中下架。后来,我不得不想办法保护自己免受这些机器人的侵害。就在那时,我开始使用 zip 炸弹。
Zip 炸弹是一种相对较小的压缩文件,但它可以扩展为非常大的文件,从而压垮机器。
早期在网络上开发的一个功能是使用 gzip 进行压缩。由于互联网速度慢且信息密集,其理念是在传输数据之前尽可能地压缩数据。因此,一个由文本组成的 50 KB HTML 文件可以压缩到 10 KB,从而节省 40 KB 的传输空间。在拨号上网的情况下,这意味着下载页面只需 3 秒,而不是 12 秒。
同样的压缩技术也适用于 CSS、JavaScript 甚至图像。Gzip 快速、简单,并能显著提升浏览体验。
浏览器发出 Web 请求时,会包含标头,告知目标服务器其支持压缩。如果服务器也支持压缩,则会返回预期数据的压缩版本。
Accept-Encoding: gzip, deflate
爬取网络的机器人也支持此功能。由于它们的任务是从网络各处获取数据,因此它们会使用压缩来最大化带宽。我们可以充分利用此功能。
在这个博客上,我经常会遇到扫描安全漏洞的机器人,而我通常都会忽略它们。但当我检测到它们试图注入恶意攻击或探测响应时,我会返回 200 OK 响应,并向它们发送 gzip 压缩包。我接收的文件大小从 1MB 到 10MB 不等,它们很乐意接收。
大多数情况下,即使它们接收了,我也再也没有收到任何消息。为什么?因为它们在接收文件后就崩溃了。
Content-Encoding: deflate, gzip
实际情况是,他们收到文件后,读取文件头,发现这是一个压缩文件。于是他们尝试解压这个 1MB 的文件,寻找所需的内容。但文件不断膨胀,直到内存耗尽,服务器崩溃。1MB 的文件解压后变成了 1GB。这足以摧毁大多数机器人。
不过,对于那些不停歇的烦人脚本,我会给他们提供 10MB 的文件。这个文件解压后变成了 10GB,脚本瞬间就被干掉了。
在告诉你如何制作 Zip 炸弹之前,我必须先警告你,你的设备可能会崩溃甚至被毁。继续操作需自行承担风险。
以下是制作 Zip 炸弹的方法:
dd if=/dev/zero bs=1G count=10 | gzip -c > 10GB.gz
我将该命令的作用解释如下:
dd
:dd命令用于复制或转换数据。if
:输入文件,指定/dev/zero
产生无限零字节流的特殊文件。bs
:块大小,将块大小设置为 1 千兆字节 (1G),这意味着 dd 将一次以 1 GB 的块读取和写入数据。count=10
:这告诉 dd 处理 10 个块,每个块大小为 1 GB。因此,这将生成 10 GB 的零数据。然后,我们将命令的输出传递给 gzip,它会将输出压缩成 10GB.gz 文件。在本例中,生成的文件大小为 10MB。
在我的服务器上,我添加了一个中间件,用于检查当前请求是否恶意。我设置了一个黑名单 IP 地址列表,这些 IP 地址会反复尝试扫描整个网站。我还设置了其他启发式方法来检测垃圾邮件发送者。许多垃圾邮件发送者会尝试向某个页面发送垃圾邮件,然后再回来查看垃圾邮件是否已经到达该页面。我使用以下模式来检测它们。
它看起来像这样:
if(ipIsBlackListed() || isMalicious()) {
header("Content-Encoding: deflate, gzip");
header("Content-Length: " + filesize(ZIP_BOMB_FILE_10G));//10 MB
readfile(ZIP_BOMB_FILE_10G);
exit;
}
还有一点,Zip 炸弹并非万无一失。它很容易被检测到并规避。毕竟,你只能读取部分内容。但对于那些盲目爬取网页、扰乱服务器的不熟练机器人来说,Zip 炸弹已经足够保护你的服务器了。
制造ZIP炸弹方法之二
首先,我们加点量,先创建一个 10GB 的 GZIP 文件,文件内容全部为零。我们可以进行多次压缩,目前先简单处理一下。
dd if=/dev/zero bs=1M count=10240 | gzip > 10G.gzip
//prepare the client to recieve GZIP data. This will not be suspicious
//since most web servers use GZIP by default
header("Content-Encoding: gzip");
header("Content-Length: ".filesize('10G.gzip'));
//Turn off output buffering
if (ob_get_level()) ob_end_clean();
//send the gzipped file to the client
readfile('10G.gzip');
好的,就是这样!
因此我们可以用它作为一个简单的防御,像这样的:
$agent = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT');
//check for nikto, sql map or "bad" subfolders which only exist on wordpress
if (strpos($agent, 'nikto') !== false || strpos($agent, 'sqlmap') !== false || startswith($url,'wp-') || startswith($url,'wordpress') || startswith($url,'wp/'))
{
sendBomb();
exit();
}
function sendBomb(){
//prepare the client to recieve GZIP data. This will not be suspicious
//since most web servers use GZIP by default
header("Content-Encoding: gzip");
header("Content-Length: ".filesize('10G.gzip'));
//Turn off output buffering
if (ob_get_level()) ob_end_clean();
//send the gzipped file to the client
readfile('10G.gzip');
}
function startsWith($a, $b) {
return strpos($a, $b) === 0;
}
正如我们在上面所说的那样,这个脚本显然不是鸡蛋的黄色,但它可以防御我之前提到的那些脚本小子,他们不知道所有这些工具都有更改用户代理的参数。
你可能注意到了动画中的小爆炸。让我来解释一下。
有一天,我发现一个网站正在实时窃取我的内容。每当有人访问他们的页面时,他们就会抓取我的博客文章,替换掉我的品牌标识,并将其据为己有。
一开始,我手动反击,给他们输入了假数据。但很快就没用了。所以我动用了我的秘密武器:给它来一个 zip 炸弹。
当他们的机器人访问我的网站时,我向它提供了一个很小的压缩文件。他们的服务器迫不及待地下载并解压了它,结果却带来了好几 GB的混乱数据。💥砰砰砰!游戏结束。
多年来,zip 炸弹已经成为我抵御试图抓取、利用或滥用我的网站的机器人的 盾牌。
作者:行动中的大雄
参考:
https://idiallo.com/blog/pc-is-not-dead-no-need-for-new-ones
https://github.com/ibudiallo/reqvis
本文为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。