Skip to content

Commit 189279f

Browse files
committed
过滤静态文件请求
0 parents  commit 189279f

File tree

17 files changed

+1822
-0
lines changed

17 files changed

+1822
-0
lines changed

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# http-guard
2+
3+
HttpGuard是基于openresty,以lua脚本语言开发的防cc攻击软件。而openresty是集成了高性能web服务器Nginx,以及一系列的Nginx模块,这其中最重要的,也是我们主要用到的nginx lua模块。HttpGuard基于nginx lua开发,继承了nginx高并发,高性能的特点,可以以非常小的性能损耗来防范大规模的cc攻击。
4+
5+
下面介绍HttpGuard防cc的一些特性:
6+
7+
1. 限制单个IP或者UA在一定时间内的请求次数
8+
2. 向访客发送302转向响应头来识别恶意用户,并阻止其再次访问
9+
3. 向访客发送带有跳转功能的js代码来识别恶意用户,并阻止其再次访问
10+
4. 向访客发送cookie来识别恶意用户,并阻止其再次访问
11+
5. 支持向访客发送带有验证码的页面,来进一步识别,以免误伤
12+
6. 支持直接断开恶意访客的连接
13+
7. 支持结合iptables来阻止恶意访客再次连接
14+
8. 支持白名单/黑名单功能
15+
9. 支持根据统计特定端口的连接数来自动开启或关闭防cc模式
16+
17+
## 部署HttpGuard
18+
### 安装openresty或者nginx lua
19+
20+
按照openresty官网手动安装[http://openresty.com](http://openresty.com)
21+
22+
### 安装HttpGuard
23+
24+
假设我们把HttpGuard安装到/data/www/waf/,当然你可以选择安装在任意目录。
25+
26+
```
27+
cd /data/www
28+
wget --no-check-certificate https://github.com/wenjun1055/HttpGuard/archive/master.zip
29+
unzip master.zip
30+
mv HttpGuard-master waf
31+
```
32+
33+
### 生成验证码图片
34+
35+
为了支持验证码识别用户,我们需要先生成验证码图片。生成验证码图片需要系统安装有php,以及php-gd模块。
36+
用以下命令执行getImg.php文件生成验证码
37+
38+
```
39+
cd /data/www/waf/captcha/
40+
/usr/local/php/bin/php getImg.php
41+
```
42+
43+
大概要生成一万个图片,可能需要花几分钟的时间。
44+
45+
### 修改nginx.conf配置文件
46+
47+
向http区块输入如下代码:
48+
49+
```
50+
lua_package_path "/data/www/waf/?.lua";
51+
lua_shared_dict guard_dict 100m;
52+
lua_shared_dict dict_captcha 70m;
53+
init_by_lua_file '/data/www/waf/init.lua';
54+
access_by_lua_file '/data/www/waf/runtime.lua';
55+
lua_max_running_timers 1;
56+
```
57+
58+
### 配置HttpGuard
59+
60+
详细配置说明在[config.lua](https://github.com/wenjun1055/HttpGuard/blob/master/guard.lua)中,请根据需求进行配置

captcha/getImg.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
function getAuthImage($text) {
3+
$im_x = 160;
4+
$im_y = 40;
5+
$im = imagecreatetruecolor($im_x,$im_y);
6+
$text_c = ImageColorAllocate($im, mt_rand(0,100),mt_rand(0,100),mt_rand(0,100));
7+
$tmpC0=mt_rand(100,255);
8+
$tmpC1=mt_rand(100,255);
9+
$tmpC2=mt_rand(100,255);
10+
$buttum_c = ImageColorAllocate($im,$tmpC0,$tmpC1,$tmpC2);
11+
imagefill($im, 16, 13, $buttum_c);
12+
13+
$font = __DIR__ . '/t1.ttf';
14+
15+
for ($i=0;$i<strlen($text);$i++)
16+
{
17+
$tmp =substr($text,$i,1);
18+
$array = array(-1,1);
19+
$p = array_rand($array);
20+
$an = $array[$p]*mt_rand(1,10);//角度
21+
$size = 28;
22+
imagettftext($im, $size, $an, 15+$i*$size, 35, $text_c, $font, $tmp);
23+
}
24+
25+
26+
$distortion_im = imagecreatetruecolor ($im_x, $im_y);
27+
28+
imagefill($distortion_im, 16, 13, $buttum_c);
29+
for ( $i=0; $i<$im_x; $i++) {
30+
for ( $j=0; $j<$im_y; $j++) {
31+
$rgb = imagecolorat($im, $i , $j);
32+
if( (int)($i+20+sin($j/$im_y*2*M_PI)*10) <= imagesx($distortion_im)&& (int)($i+20+sin($j/$im_y*2*M_PI)*10) >=0 ) {
33+
imagesetpixel ($distortion_im, (int)($i+10+sin($j/$im_y*2*M_PI-M_PI*0.1)*4) , $j , $rgb);
34+
}
35+
}
36+
}
37+
//加入干扰象素;
38+
$count = 160;//干扰像素的数量
39+
for($i=0; $i<$count; $i++){
40+
$randcolor = ImageColorallocate($distortion_im,mt_rand(0,255),mt_rand(0,255),mt_rand(0,255));
41+
imagesetpixel($distortion_im, mt_rand()%$im_x , mt_rand()%$im_y , $randcolor);
42+
}
43+
44+
$rand = mt_rand(5,30);
45+
$rand1 = mt_rand(15,25);
46+
$rand2 = mt_rand(5,10);
47+
for ($yy=$rand; $yy<=+$rand+2; $yy++){
48+
for ($px=-80;$px<=80;$px=$px+0.1)
49+
{
50+
$x=$px/$rand1;
51+
if ($x!=0)
52+
{
53+
$y=sin($x);
54+
}
55+
$py=$y*$rand2;
56+
57+
imagesetpixel($distortion_im, $px+80, $py+$yy, $text_c);
58+
}
59+
}
60+
61+
//设置文件头;
62+
//Header("Content-type: image/JPEG");
63+
64+
//以PNG格式将图像输出到浏览器或文件;
65+
$fileName = $text . ".png";
66+
ImagePNG($distortion_im,$fileName);
67+
68+
//销毁一图像,释放与image关联的内存;
69+
ImageDestroy($distortion_im);
70+
ImageDestroy($im);
71+
}
72+
73+
function make_rand($length="32"){//验证码文字生成函数
74+
$str="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
75+
$result="";
76+
for($i=0;$i<$length;$i++){
77+
$num[$i]=rand(0,35);
78+
$result.=$str[$num[$i]];
79+
}
80+
return $result;
81+
}
82+
83+
84+
//输出调用
85+
for ($i=1;$i<=10200;$i++) {
86+
$checkcode = make_rand(4);
87+
getAuthImage($checkcode);
88+
}
89+
90+
?>
91+

captcha/t1.ttf

34 KB
Binary file not shown.

config.lua

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
-- http-guard安装目录,修改为实际安装到的目录。
2+
baseDir = '/etc/flamingo/openresty/script/waf/'
3+
4+
local Config = {
5+
-- key是否动态生成,可选static,dynamic,如果选dynamic,下面所有的keySecret不需要更改,如果选static,修改手动修改下面的keySecret
6+
keyDefine = "dynamic",
7+
8+
-- 被动防御,限制UA请求模块。根据在一定时间内统计到的单个UA请求次数作限制(专门针对火车头采集工具)
9+
-- state : 为此模块的状态,表示开启或关闭,可选值为On或Off;
10+
-- maxReqs,amongTime : 在amongTime秒内允许请求的最大次数maxReqs,如默认的是在10s内最大允许请求50次。
11+
limitUaModules = { state = "On" , maxReqs = 50 , amongTime = 10},
12+
13+
-- 被动防御,限制请求模块。根据在一定时间内统计到的请求次数作限制,建议始终开启
14+
-- state : 为此模块的状态,表示开启或关闭,可选值为On或Off;
15+
-- maxReqs,amongTime : 在amongTime秒内允许请求的最大次数maxReqs,如默认的是在10s内最大允许请求50次。
16+
-- urlProtect : 指定限制请求次数的url正则表达式文件,默认值为\.php$,表示只限制php的请求(当然,当urlMatchMode = "uri"时,此正则才能起作用)
17+
limitReqModules = { state = "On" , maxReqs = 50 , amongTime = 10, urlProtect = baseDir.."url-protect/limit.txt" },
18+
19+
20+
-- 主动防御,302响应头跳转模块。利用cc控制端不支持解析响应头的特点,来识别是否为正常用户,当有必要时才建议开启。
21+
-- state : 为此模块的状态,表示开启或关闭,可选值为On或Off;
22+
-- verifyMaxFail amongTime : 因为此模块会发送带有cckey及keyexpire的302响应头,如果访客在amongTime时间内超过verifyMaxFail次没有跳转到302响应头里的url,就会被添加到黑名单,默认值为5次。
23+
-- keySecret : 用于生成token的密码,如果上面的keyDefine为dynamic,就不需要修改
24+
-- urlProtect 同limitReqModules模块中的urlProtect的解释。
25+
redirectModules = { state = "Off" ,verifyMaxFail = 5, keySecret = 'yK48J276hg', amongTime = 60 ,urlProtect = baseDir.."url-protect/302.txt"},
26+
27+
28+
-- 主动防御,发送js跳转代码模块。利用cc控制端无法解析js跳转的特点,来识别是否为正常用户,当有必要时才建议开启。
29+
-- state : 为此模块的状态,表示开启或关闭,可选值为On或Off;
30+
-- verifyMaxFail amongTime : 因为此模块会发送带有js跳转代码的响应体,如果访客在amongTime时间内超过verifyMaxFail次没有跳转到js跳转代码里的url,就会被添加到黑名单,默认值为5次。
31+
-- keySecret : 用于生成token的密码,如果上面的keyDefine为dynamic,就不需要修改
32+
-- urlProtect 同limitReqModules模块中的urlProtect的解释。
33+
JsJumpModules = { state = "Off" ,verifyMaxFail = 5, keySecret = 'QSjL6p38h9', amongTime = 60 , urlProtect = baseDir.."url-protect/js.txt"},
34+
35+
-- 主动防御,发送cookie验证模块。此模块会向访客发送cookie,然后等待访客返回正确的cookie,此模块利用cc控制端无法支持cookie的特点,来识别cc攻击,当有必要时才建议开启
36+
-- state : 为此模块的状态,表示开启或关闭,可选值为On或Off;
37+
-- verifyMaxFail amongTime : 因为此模块会发送cookie,如果访客在amongTime时间内超过verifyMaxFail次没有返回正确的cookie,就会被添加到黑名单,默认值为5次。
38+
-- keySecret : 用于生成token的密码,如果上面的keyDefine为dynamic,就不需要修改
39+
-- urlProtect 同limitReqModules模块中的urlProtect的解释。
40+
cookieModules = { state = "Off" ,verifyMaxFail = 5, keySecret = 'bGMfY2D5t3', amongTime = 60 , urlProtect = baseDir.."url-protect/cookie.txt"},
41+
42+
-- 自动开启主动防御,原理是根据protectPort端口的已连接数超过maxConnection来确定
43+
-- state : 为此模块的状态,表示开启或关闭,可选值为On或Off;
44+
-- interval 间隔30秒检查一次连接数,默认为30秒。
45+
-- protectPort,maxConnection,normalTimes,exceedTimes : enableModule中的模块为关闭状态时,当端口protectPort的连接数连续exceedTimes次超过maxConnection时,开启enableModule中的模块;
46+
-- enableModule中的模块为开启状态时,当端口protectPort的连接数连续normalTimes次低于maxConnection时,关闭enableModule中的模块。
47+
-- ssCommand : 我们是使用ss命令来检查特定端口的已连接的连接数,ss命令比同类的命令netstat快得多。请把ss命令的路径改为自己系统上的路径。
48+
-- enableModules : 自动启动哪个主动防御模块,可选值为redirectModules JsJumpModules cookieModules
49+
autoEnable = { state = "Off", protectPort = "80", interval = 30, normalTimes = 3,exceedTimes = 2,maxConnection = 500, ssCommand = "/usr/sbin/ss" ,enableModule = "redirectModules"},
50+
51+
-- 用于当输入验证码验证通过时,生成key的密码.如果上面的keyDefine为dynamic,就不需要修改
52+
captchaKey = "K4QEaHjwyF",
53+
54+
-- ip在黑名单时执行的动作(可选值captcha,forbidden,iptables)
55+
-- 值为captcha时,表示ip在黑名单后返回带有验证码的页面,输入正确的验证码才允许继续访问网站
56+
-- 值为forbidden时,表示ip在黑名单后,服务器会直接断开与用户的连接.
57+
-- 值为iptables时,表示ip在黑名单后,http-guard会用iptables封锁此ip的连接
58+
-- 当值为iptables时,需要为nginx运行用户设置密码及添加到sudo以便能执行iptables命令。假设nginx运行用户为www,设置方法为:
59+
-- 1.设置www密码,命令为passwd www
60+
-- 2.以根用户执行visudo命令,添加www ALL=(root) /sbin/iptables -I INPUT -p tcp -s [0-9.]* --dport 80 -j DROP
61+
-- 3.以根用户执行visudo命令,找到Default requiretty注释,即更改为#Default requiretty,如果找不到此设置,就不需要改。
62+
-- blockAction = "captcha",
63+
blockAction = "forbidden",
64+
65+
-- nginx运行用户的sudo密码,blockAction值为iptables需要设置,否则不需要
66+
sudoPass = '',
67+
68+
-- 表示http-guard封锁ip的时间
69+
blockTime = 86400,
70+
71+
-- JsJumpModules redirectModules cookieModules验证通过后,ip在白名单的时间
72+
whiteTime = 600,
73+
74+
-- 用于生成token密码的key过期时间
75+
keyExpire = 600,
76+
77+
-- 匹配url模式,可选值requestUri,uri
78+
-- 值requestUri时,url-protect目录下的正则匹配的是浏览器最初请求的地址且没有被decode,带参数的链接
79+
-- 值为uri时, url-protect目录下的正则匹配的是经过重写过的地址,不带参数,且已经decode.
80+
urlMatchMode = "uri",
81+
82+
-- 验证码页面路径,一般不需要修改
83+
captchaPage = baseDir.."html/captcha.html",
84+
85+
-- 输入验证码错误时显示的页面路径,一般不需要修改
86+
reCaptchaPage = baseDir.."html/reCatchaPage.html",
87+
88+
-- 白名单ip文件,文件内容为正则表达式。
89+
whiteIpModules = { state = "On", ipList = baseDir.."url-protect/white_ip_list.txt" },
90+
91+
-- 黑名单ip文件,文件内容为正则表达式。
92+
blackIpModules = { state = "Off", ipList = baseDir.."url-protect/black_ip_list.txt" },
93+
94+
-- 如果需要从请求头获取真实ip,此值就需要设置,如x-forwarded-for
95+
-- 当state为on时,此设置才有效
96+
realIpFromHeader = { state = "Off", header = "x-forwarded-for"},
97+
98+
-- 指定验证码图片目录,一般不需要修改
99+
captchaDir = baseDir.."captcha/",
100+
101+
-- 是否开启debug日志
102+
debug = true,
103+
104+
--日志目录,一般不需要修改.但需要设置logs所有者为nginx运行用户,如nginx运行用户为www,则命令为chown www logs
105+
logPath = baseDir.."logs/",
106+
107+
-- 正则匹配静态文件
108+
staticRegex = [[.*?\.(css|js|jpg|jpeg|png|ico|svg|swf)$]],
109+
}
110+
111+
return Config

0 commit comments

Comments
 (0)