防御CC只能放大招

作者: K-Joker 分类: shell脚本 发布时间: 2018-10-01 04:59

  什么是CC

攻 击者借助代理服务器生成指向受害主机的合法请求,实现DDOS和伪装就叫:CC,全称叫ChallengeCollapsar。相信大家都有这样的经历,有时候访问网站超级慢,甚至是无法访问,到服务器上看发现同一个IP或者多个IP访问一分钟之内访问了几百万次,这就是被CC攻 击了,CC攻 击属于DDos攻 击的一种,攻 击者会利用大量的“肉鸡”对目标网站发起请求,而且频率超级超级的快,这样子就会导致服务器承受不住而瘫痪。CC攻 击虽然看起来和正常访问几乎没什么区别,有时候甚至还会模仿正规的搜索引擎,把自己伪装成百度、谷歌等等

  如何防御

防御CC攻 击首先需要从根本上做起,禁止网站代理访问,尽量将网站做成静态页面,限制连接数量,修改最大超时时间,当然也有非常直接的方法,就是从日志中分析出所有可能是”肉鸡”的IP地址然后将其写入iptables防火墙中拒绝访问,此文就具体的介绍如何使用脚本实现自动化的拒绝这些IP访问

  分析日志格式

使用head命令查看前几行的的日志格式从而分析,但说白了关心的东西也就那么几点,首先是第一个字段,这是请求过来的真是IP地址,其次则是,requesthost后面说跟着的字段,则是请求访问的域名

47.52.16.198 - - [01/Oct/2018:03:24:17 +0800] requesthost:"www.a.com"; "GET /ocs/v2.php/apps/notifications/api/v2/notifications HTTP/1.1" requesttime:"0.299"; 200 74 "-" - -"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" "-"

分析完成后,我们接下来需要确定一下整体的思路流程

  1. 把一分钟之内访问超过100次的IP地址给拒绝访问
  2. 拒绝的IP地址需要记录到一个日志当中
  3. 每次进行检测前把之前的IP解除拒绝访问
  4. 解除拒绝访问的IP地址也需要记录到一个日志当中

这里给大家介绍一个实际的生产案列,在之前的碰壁当中,使用脚本自动化去实现防御CC会存在误封掉正常的请求,因为真的有些客户会一直去点击刷新页面(我也很无奈,我也很无语),所以面对这种情况,建议是将IP使用iptables去转发,呈现客户一个纯静态的页面,提示用户请求次数过多一分钟之后在尝试访问,最后一分钟之后自动解封。

  awk处理字符串

awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。

语法形式

awk [options] ‘script’ var=value file(s)
awk [options] -f scriptfile var=value file(s)

常用命令选项

-F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value 赋值一个用户定义变量,将外部变量传递给awk
-f scripfile 从脚本文件中读取awk命令
-m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。

在这里使用a.txt文本做几个简单的操作演示,a.txt内容如下:
1:2:3
6#5#4
7:8:9

#截取指定段
[root@test ~]# awk -F ':|#' '{print $2}' a.txt
2
5
8

#匹配字符后字符串
[root@center ~]# awk -F':|#' '$1 ~ "^[0-9]"' a.txt 
1:2:3
6#5#4
7:8:9

  sort排序

sort命令是在Linux里非常有用,它可以将文件进行排序,并将排序结果标准输出。sort命令既可以从特定的文件,也可以从stdin中获取输入。

语法形式

sort(选项)(参数)

常用命令选项

-b:忽略每行前面开始出的空格字符;
-c:检查文件是否已经按照顺序排序;
-d:排序时,处理英文字母、数字及空格字符外,忽略其他的字符;
-f:排序时,将小写字母视为大写字母;
-i:排序时,除了040至176之间的ASCII字符外,忽略其他的字符;
-m:将几个排序号的文件进行合并;
-M:将前面3个字母依照月份的缩写进行排序;
-n:依照数值的大小排序;
-o<输出文件>:将排序后的结果存入制定的文件;
-r:以相反的顺序来排序;
-t<分隔字符>:指定排序时所用的栏位分隔字符;
+<起始栏位>-<结束栏位>:以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。

在这里使用a.txt文本做几个简单的操作演示,a.txt内容如下:
D-127.0.0.1
C-10.0.0.1
B-172.16.0.1
A-192.168.0.1

#简单排序
[root@center ~]# cat a.txt | sort
A-192.168.0.1
B-172.16.0.1
C-10.0.0.1
D-127.0.0.1

#反向排序
[root@center ~]# cat a.txt | sort -r
D-127.0.0.1
C-10.0.0.1
B-172.16.0.1
A-192.168.0.1

  uniq去除重复

uniq命令用于报告或忽略文件中的重复行,一般与sort命令结合使用。
语法形式

uniq(选项)(参数)

常用命令选项

-c或——count:在每列旁边显示该行重复出现的次数;
-d或–repeated:仅显示重复出现的行列;
-f<栏位>或–skip-fields=<栏位>:忽略比较指定的栏位;
-s<字符位置>或–skip-chars=<字符位置>:忽略比较指定的字符;
-u或——unique:仅显示出一次的行列;
-w<字符位置>或–check-chars=<字符位置>:指定要比较的字符。

在这里使用a.txt文本做几个简单的操作演示,a.txt内容如下:
192.168.0.1
192.168.0.1
192.168.0.1
10.0.0.1

#去除重复并统计重复个数
[root@center ~]# cat a.txt | uniq -c
    3 192.168.0.1
    1 10.0.0.1

*这里要注意的是要先排好序然后才能正常统计,所以一般会和sort搭配使用

  脚本案例

有了前面的三个的介绍,那么接下来看下面的示例脚本相信你会更容易一些

#########################################################################
# File Name: CC_Attack.sh
# Author: K-Joker
# mail: keminwu.love@gmail.com
# Created Time: Sun 30 Sep 2018 07:53:19 AM CST
#########################################################################

#!/bin/bash

#定义访问日志的路径
Log_Path=/var/log/nginx/access.log

#定义临时存放一分钟之前的日志文件路径
Tmp_Log=/tmp/tmp_last_min.log
#定义一个存放一分钟访问量高于10次的IP地址临时文件
Tmp_IP=/tmp/tmp_ip

#定义防御攻击脚本的日志
Attack_Log=/var/log/nginx/attack.log



################################
#统计一分钟之前的日志相关信息的方法
################################
AccessLog()
{
	
	#将一分钟之前的日志输出到一个临时的文件中
	egrep "$OneMinAgo:[0-5]+" $Log_Path > $Tmp_Log
	#将这一分钟的日志输出到一个临时的文件中
	egrep "$NowTime:[0-5]+" $Log_Path >> $Tmp_Log

}



####################################################
#将一分钟内访问次数超过10次的IP转发到另外的一个页面的方法
####################################################
Block_IP()
{

	#把一分钟内访问超过10次的IP地址统计到一个临时文件中
	awk '{print $1,$6}' $Tmp_Log | awk -F'requesthost:"|";' '{print $1,$2}' | sort -n | uniq -c | awk '$1>10 {print $2,$3}' > $Tmp_IP
	#重写Tmp_IP文件格式
	sed -i 's/[ ][ ]*/,/g' $Tmp_IP
	#统计将要转发的IP个数
	count=`wc -l $Tmp_IP | awk '{ print $1 }'`

	#判断IP数量是否大于0
	if [ $count -ne 0 ]
	then
		for recording in `cat $Tmp_IP`
		do
			ip=`echo $recording | awk -F',' '{print $1}'`
			domain=`echo $recording | awk -F',' '{print $2}'`
			#添加规则将请求转发到其他服务器上的80和443端口
			iptables -I FORWARD -s $ip  -j ACCEPT
			iptables -t nat -I POSTROUTING -s $ip -j SNAT --to-source 172.31.243.145
			iptables -t nat -I PREROUTING -i eth0 -p tcp -s $ip --dport 80 -j DNAT --to-destination 112.74.169.181:80
			iptables -t nat -I PREROUTING -i eth0 -p tcp -s $ip --dport 443 -j DNAT --to-destination 112.74.169.181:443
			#将IP记录到日志文件当中
			echo "`date` [INFO] $ip -- $domain Too many requests Forward Warning Page !" >> $Attack_Log
		done
	fi

}



#########################
#解封一分钟之前的IP地址方法
#########################
UnBlock_IP()
{

	#统计之前被转发的IP个数
	count=`wc -l $Tmp_IP | awk '{ print $1 }'`

	#判断IP数量是否大于0
	if [ $count -ne 0 ]
	then
		for ip in `cat $Tmp_IP | awk -F',' '{ print $1 }'`
		do
			#将请求转发到警告服务器上的80和443端口的规则移除
			iptables -D FORWARD -s $ip  -j ACCEPT
			iptables -t nat -D POSTROUTING -s $ip -j SNAT --to-source 172.31.243.145
			iptables -t nat -D PREROUTING -i eth0 -p tcp -s $ip --dport 80 -j DNAT --to-destination 112.74.169.181:80
			iptables -t nat -D PREROUTING -i eth0 -p tcp -s $ip --dport 443 -j DNAT --to-destination 112.74.169.181:443
			#将IP记录到日志文件当中
			echo "`date` [INFO] $ip -- Delimitation time !" >> $Attack_Log
		done
	fi

}



#########
#程序主体
#########
while true

	#定义一分钟之前的时间
	OneMinAgo=`date -d "-1 min" +%Y:%H:%M`
	#定义目前的时间
	NowTime=`date +%Y:%H:%M`

	#执行解除转发规则方法
	UnBlock_IP
	sleep 2s
	
	#执行统计方法
	AccessLog
	sleep 2s

	#执行转发规则方法
	Block_IP
	if [ `wc -l $Tmp_IP | awk '{ print $1 }'` -ne 0 ]
	then
		sleep 50s
	else
		sleep 5s
	fi

done

这里需要注意几点的是,案例里的阈值设为10次每分钟是为了能测出效果,还有就是执行转发是否休眠时间需要根据服务器性能而定,脚本可以使用nohup放在后台直接执行,无需使用计划任务,当然也可以修改一下然后放计划任务里面执行,这里需要注意计划任务是否有权限执行iptables这个命令

哟,老板,有空常来呀~

发表评论

电子邮件地址不会被公开。