记一次悲剧的网站负载过高(被攻击?)的经历

从昨天开始,uptimerobot就一直在给我发我的某一个网站 currently DOWN (Bad Gateway) ,以前有过这样的情况,但一般也就是持续很短的时间,昨天以为也这样就没管,没想到今天了还是这样,没办法,得处理一下。
我的网站是一个需要频繁采集的网站,基本上每个请求都需要对外采集信息,而且买的是比较便宜的VPS,本来负载能力就不高,上面装的是lnmp.org提供的一键安装环境,其中mysql还没启(不在一台机子上),一般访问还是能抗住。
以前这个机子有过这样的经历,那次经过我N久的寻找,发现他们主机商提供的DNS挂了,从那以后就换成了8.8.8.8,这次当然第一步还是检测这个,然后发现不是这个问题。
当时突然想到这台机子还有我的一个简易监控脚本,上去一看吓一跳。

从昨天中午开始,访问一下就上来了,难道是被攻击了?

以前没有开nginx日志,这次先给开开,然后就发现….尼玛….UA全是AOLBuild,而且有大量的非重复IP,每秒几十次!知道原因就好说了,封了这个。

以前经历过被百度蜘蛛给整挂了,那时候就是判断了一下UA,然后给die()掉,这次也在入口文件上写上这个,发现竟然没用!

没办法,换思路,记下这帮AOLBuild的IP地址,用iptables给封掉,虽然说非常重复IP挺多,然是还是能统计的。

一开始是简单随便实现了一下,这里后来做了修改,封装成了一个类,就是记录UA包含AOLBuild的IP地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class MyACL{
public $UAarr;
public $fileDir;
public $retClient;
public function __construct($UAarr="",$fileDir="iplist.txt",$retClient=null){
$this->UAarr = $UAarr;
$this->fileDir = $fileDir;
}
public function get_ip(){
if (!empty($_SERVER["HTTP_CLIENT_IP"])){
$ip = $_SERVER["HTTP_CLIENT_IP"];
}
else if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])){
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}
else if (!empty($_SERVER["REMOTE_ADDR"])){
$ip = $_SERVER["REMOTE_ADDR"];
}
$preg="/\A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\Z/";
if(preg_match($preg,$ip)&&$ip!="127.0.0.1"){
return $ip;
}else{
return FALSE;
}
}
public function write_file($cont){
if(!$cont)return;
$isHave = shell_exec("grep '$cont' ".$this->fileDir);
if(!$isHave){
$fp = fopen($this->fileDir,'a+');
fwrite($fp,$cont."\n");
}
}
public function ret_client(){
@header("http/1.1 404 not found");
@header("status: 404 not found");
die();
}
public function run(){
if(is_array($this->UAarr)){
foreach($this->UAarr as $uavo){
if(@strpos($_SERVER['HTTP_USER_AGENT'], $uavo) >0){
$this->write_file($uavo."\t".$this->get_ip());
break;
}
}
}else{
$this->write_file($this->get_ip());
}
if($this->retClient!=null)ret_client();
}

}

这个类引入到网站入口文件,实例化后运行一会,下一步,给封掉,执行

1
for line in $(cat iplist.log | awk '{print $2}'); do iptables -I INPUT -s $line -j DROP; done

OK,跑了段时间看了一下,效果很显著,基本上不会被跑挂了,隔一会可以执行

1
iptables -F

给清空掉,然后在重来一遍上面的指令,增加一批封锁的IP