diff --git a/README.md b/README.md index bc35065..3110d01 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,60 @@ -http-guard -========== +# http-guard -prevent cc attack +HttpGuard是基于openresty,以lua脚本语言开发的防cc攻击软件。而openresty是集成了高性能web服务器Nginx,以及一系列的Nginx模块,这其中最重要的,也是我们主要用到的nginx lua模块。HttpGuard基于nginx lua开发,继承了nginx高并发,高性能的特点,可以以非常小的性能损耗来防范大规模的cc攻击。 + +下面介绍HttpGuard防cc的一些特性: + +1. 限制单个IP或者UA在一定时间内的请求次数 +2. 向访客发送302转向响应头来识别恶意用户,并阻止其再次访问 +3. 向访客发送带有跳转功能的js代码来识别恶意用户,并阻止其再次访问 +4. 向访客发送cookie来识别恶意用户,并阻止其再次访问 +5. 支持向访客发送带有验证码的页面,来进一步识别,以免误伤 +6. 支持直接断开恶意访客的连接 +7. 支持结合iptables来阻止恶意访客再次连接 +8. 支持白名单/黑名单功能 +9. 支持根据统计特定端口的连接数来自动开启或关闭防cc模式 + +## 部署HttpGuard +### 安装openresty或者nginx lua + +按照openresty官网手动安装[http://openresty.com](http://openresty.com) + +### 安装HttpGuard + +假设我们把HttpGuard安装到/data/www/waf/,当然你可以选择安装在任意目录。 + +``` +cd /data/www +wget --no-check-certificate https://github.com/wenjun1055/HttpGuard/archive/master.zip +unzip master.zip +mv HttpGuard-master waf +``` + +### 生成验证码图片 + +为了支持验证码识别用户,我们需要先生成验证码图片。生成验证码图片需要系统安装有php,以及php-gd模块。 +用以下命令执行getImg.php文件生成验证码 + +``` +cd /data/www/waf/captcha/ +/usr/local/php/bin/php getImg.php +``` + +大概要生成一万个图片,可能需要花几分钟的时间。 + +### 修改nginx.conf配置文件 + +向http区块输入如下代码: + +``` +lua_package_path "/data/www/waf/?.lua"; +lua_shared_dict guard_dict 100m; +lua_shared_dict dict_captcha 70m; +init_by_lua_file '/data/www/waf/init.lua'; +access_by_lua_file '/data/www/waf/runtime.lua'; +lua_max_running_timers 1; +``` + +### 配置HttpGuard + +详细配置说明在[config.lua](https://github.com/wenjun1055/HttpGuard/blob/master/guard.lua)中,请根据需求进行配置 \ No newline at end of file diff --git a/captcha/getImg.php b/captcha/getImg.php index c976054..0daa5af 100644 --- a/captcha/getImg.php +++ b/captcha/getImg.php @@ -10,7 +10,7 @@ function getAuthImage($text) { $buttum_c = ImageColorAllocate($im,$tmpC0,$tmpC1,$tmpC2); imagefill($im, 16, 13, $buttum_c); - $font = '/data/www/waf/captcha/t1.ttf'; + $font = __DIR__ . '/t1.ttf'; for ($i=0;$i _Conf.limitUaModules.maxReqs then --判断是否请求数大于阀值 + self:debug("[limitUaModules] ip "..ip.. " request exceed ".._Conf.limitUaModules.maxReqs.." "..userAgent, ip, reqUri) + _Conf.dict:set(blackUaKey, 0, _Conf.blockTime) --添加此ip到黑名单 + self:log("[limitUaModules] IP "..ip.." visit "..newUaTimes.." times,block it. "..userAgent) + end + +end + + +--限制IP请求速率模块 function Guard:limitReqModules(ip,reqUri,address) if ngx.re.match(address,_Conf.limitUrlProtect,"i") then self:debug("[limitReqModules] address "..address.." match reg ".._Conf.limitUrlProtect,ip,reqUri) @@ -82,6 +159,14 @@ function Guard:limitReqModules(ip,reqUri,address) self:debug("[limitReqModules] ip "..ip.. " request exceed ".._Conf.limitReqModules.maxReqs,ip,reqUri) _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 self:log("[limitReqModules] IP "..ip.." visit "..newReqTimes.." times,block it.") + + --大于20次的特别记录下来 + if newReqTimes > 20 then + local filename = _Conf.logPath.."/large_flow.log" + local file = io.open(filename, "a+") + file:write(os.date('%Y-%m-%d %H:%M:%S').." IP "..ip.."\n") + file:close() + end end end @@ -534,8 +619,27 @@ function Guard:verifyCaptcha(ip) local captchaValue = _Conf.dict_captcha:get(captchaNum) --从字典获取post value对应的验证码值 if captchaValue == postValue then --比较验证码是否相等 self:debug("[verifyCaptcha] captcha is valid.delete from blacklist",ip,"") + _Conf.dict:delete(ip.."black") --从黑名单删除 _Conf.dict:delete(ip.."limitreqkey") --访问记录删除 + + if _Conf.limitUaModulesIsOn then + local headers = ngx.req.get_headers() + local userAgent = headers["user-agent"] + --不存在UA直接抛验证码 + if not userAgent then + self:debug("[limitUaModules] ip "..ip.." not have ua", ip, reqUri) + self:takeAction(ip,reqUri) --存在则执行相应动作 + end + + local uaMd5 = ngx.md5(userAgent) + local blackUaKey = uaMd5 .. 'BlackUAKey' + local limitUaKey = uaMd5 .. 'LimitUaKey' + + _Conf.dict:delete(blackUaKey) --从黑名单删除 + _Conf.dict:delete(limitUaKey) --访问记录删除 + end + local expire = ngx.time() + _Conf.keyExpire local captchaKey = ngx.md5(table.concat({ip,_Conf.captchaKey,expire})) local captchaKey = string.sub(captchaKey,"1","10") diff --git a/html/captcha.html b/html/captcha.html index 9124bf2..3a7dc4c 100644 --- a/html/captcha.html +++ b/html/captcha.html @@ -1,24 +1,171 @@ + - - - 请输入验证码 - - - -
-

很抱歉...

-

您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。

-

要继续访问网页,请输入下面所示字符:

-
- Captcha image + + + + 请输入验证码 + + + +
+
+
+


+
+

本站为防止被恶意攻击已开启验证机制

+

此验证页面仅在被认为恶意攻击时出现

+

您正常浏览时也有可能触发防攻击程序

+
+

请输入验证码继续访问!!!

+ +
Captcha image
+

+
+ +
- +
+
+ \ No newline at end of file diff --git a/html/captcha.old.html b/html/captcha.old.html new file mode 100644 index 0000000..9124bf2 --- /dev/null +++ b/html/captcha.old.html @@ -0,0 +1,24 @@ + + + + 请输入验证码 + + + +
+

很抱歉...

+

您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。

+

要继续访问网页,请输入下面所示字符:

+
+ Captcha image +
+
+ + \ No newline at end of file diff --git a/html/reCatchaPage.html b/html/reCatchaPage.html index 8a19567..516734c 100644 --- a/html/reCatchaPage.html +++ b/html/reCatchaPage.html @@ -1,25 +1,172 @@ + - - - 请输入验证码 - - - -
-

很抱歉...

-

您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。

-

要继续访问网页,请输入下面所示字符:

-

验证码输入错误,请重新输入

-
- Captcha image + + + + 请输入验证码 + + + +
+
+
+


+
+

本站为防止被恶意攻击已开启验证机制

+

此验证页面仅在被认为恶意攻击时出现

+

您正常浏览时也有可能触发防攻击程序

+
+

请输入验证码继续访问!!!

+

验证码输入错误,请重新输入

+ +
Captcha image
+

+
+ +
- +
+
+ \ No newline at end of file diff --git a/html/reCatchaPage.old.html b/html/reCatchaPage.old.html new file mode 100644 index 0000000..8a19567 --- /dev/null +++ b/html/reCatchaPage.old.html @@ -0,0 +1,25 @@ + + + + 请输入验证码 + + + +
+

很抱歉...

+

您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。

+

要继续访问网页,请输入下面所示字符:

+

验证码输入错误,请重新输入

+
+ Captcha image +
+
+ + \ No newline at end of file diff --git a/init.lua b/init.lua index 477c5c0..3b992af 100644 --- a/init.lua +++ b/init.lua @@ -121,6 +121,7 @@ end _Conf = { --引入原始设置 + limitUaModules = Config.limitUaModules, limitReqModules = Config.limitReqModules, redirectModules = Config.redirectModules, JsJumpModules = Config.JsJumpModules, @@ -137,8 +138,10 @@ _Conf = { captchaKey = Config.captchaKey, --解析开关设置 + limitUaModulesIsOn = optionIsOn(Config.limitUaModules.state), limitReqModulesIsOn = optionIsOn(Config.limitReqModules.state), whiteIpModulesIsOn = optionIsOn(Config.whiteIpModules.state), + fileBlackIpModulesIsOn = optionIsOn(Config.blackIpModules.state), realIpFromHeaderIsOn = optionIsOn(Config.realIpFromHeader.state), autoEnableIsOn = optionIsOn(Config.autoEnable.state), redirectModulesIsOn = optionIsOn(Config.redirectModules.state), @@ -151,6 +154,7 @@ _Conf = { limitUrlProtect = parseRuleFile(Config.limitReqModules.urlProtect), cookieUrlProtect = parseRuleFile(Config.cookieModules.urlProtect), whiteIpList = parseRuleFile(Config.whiteIpModules.ipList), + fileBlackIpList = parseRuleFile(Config.blackIpModules.ipList), --读取文件到内存 captchaPage = readFile2Mem(Config.captchaPage), diff --git a/runtime.lua b/runtime.lua index aa1d3df..c664041 100644 --- a/runtime.lua +++ b/runtime.lua @@ -28,13 +28,27 @@ else if _Conf.autoEnableIsOn then ngx.timer.at(0,Guard.autoSwitch) end - + + --永久黑名单 + if Guard:ipInFileBlackList(ip) then + ngx.exit(404) + end + --白名单模块 if not Guard:ipInWhiteList(ip) then + --收集不在白名单库里面的蜘蛛 + Guard:collectSpiderIp(ip, headers) + --黑名单模块 - Guard:blackListModules(ip,reqUri) + Guard:blackListModules(ip, reqUri, headers) + + --限制UA请求速率模块 + if _Conf.limitUaModulesIsOn then + Guard:debug("[limitUaModules] limitUaModules is on.",ip,reqUri) + Guard:limitUaModules(ip, reqUri, address, headers) + end - --限制请求速率模块 + --限制IP请求速率模块 if _Conf.limitReqModulesIsOn then --limitReq模块是否开启 Guard:debug("[limitReqModules] limitReqModules is on.",ip,reqUri) Guard:limitReqModules(ip,reqUri,address) diff --git a/logs/foo b/url-protect/black_ip_list.txt similarity index 100% rename from logs/foo rename to url-protect/black_ip_list.txt diff --git a/url-protect/limit.txt b/url-protect/limit.txt index c317c7e..2a9e9d0 100644 --- a/url-protect/limit.txt +++ b/url-protect/limit.txt @@ -1 +1,3 @@ -\.php$ \ No newline at end of file +\.php$ +\.html$ +\.png$ \ No newline at end of file diff --git a/url-protect/white_ip_list.txt b/url-protect/white_ip_list.txt index e69de29..7d30de4 100644 --- a/url-protect/white_ip_list.txt +++ b/url-protect/white_ip_list.txt @@ -0,0 +1,40 @@ +61.135.186.* +61.155.149.* +61.182.137.* +117.27.149.* +117.34.28.* +119.188.132.* +119.188.14.* +119.63.193.* +123.125.71.* +180.76.5.* +180.76.6.* +183.60.235.* +220.181.108.* +222.216.190.* +220.181.126.* +220.181.165.* +220.181.38.* +220.181.51.* +180.149.130.* +180.149.133.* +202.46.48.* +202.46.49.* +202.46.50.* +202.46.51.* +202.46.52.* +202.46.53.* +202.46.54.* +202.46.55.* +202.46.56.* +202.46.60.* +202.46.61.* +202.46.62.* +182.118.26.* +182.118.43.* +182.118.44.* +182.118.45.* +182.118.54.* +182.118.60.* +182.118.70.* +182.118.71.* \ No newline at end of file