├── .gitignore ├── Readme.txt ├── captcha ├── getImg.php └── t1.ttf ├── config.lua ├── guard.lua ├── html ├── captcha.html └── reCatchaPage.html ├── init.lua ├── runtime.lua └── url-protect ├── 302.txt ├── cookie.txt ├── js.txt ├── limit.txt ├── post.txt ├── uri.txt └── white_ip_list.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | /logs/*.log 3 | -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | 参考了:https://github.com/centos-bz/HttpGuard 2 | 3 | 该模块需要nginx lua支持,可以直接使用openresty安装使用。 4 | http://openresty.com/ 5 | 6 | 具体使用直接参考HttpGuard的使用,这个包是在HttpGuard基础上添加的 7 | 其中包括有url过滤和post提交参数过滤。 8 | 9 | 10 | 11 | 具体功能: 12 | 限制访客在一定时间内的请求次数 13 | 向访客发送302转向响应头来识别是否是恶意用户,并阻止其再次访问 14 | 向访客发送带有跳转功能的js代码来识别是否是恶意用户,并阻止其再次访问 15 | 支持向访客发送带有验证码的页面,来进一步识别,以免误伤 16 | 支持直接断开恶意访客的连接 17 | 支持结合iptables来阻止恶意访客再次连接 18 | 支持白名单功能 19 | 支持根据统计特定端口的连接数来自动开启或关闭防cc模式 20 | 21 | -------------------------------------------------------------------------------- /captcha/getImg.php: -------------------------------------------------------------------------------- 1 | =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(5); 87 | getAuthImage($checkcode); 88 | } 89 | 90 | ?> 91 | 92 | -------------------------------------------------------------------------------- /captcha/t1.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monkeyzhu123/nginx-lua-waf/e04a522fb2e46c71226b7de668b39c814c5d8562/captcha/t1.ttf -------------------------------------------------------------------------------- /config.lua: -------------------------------------------------------------------------------- 1 | -- http-guard安装目录,修改为实际安装到的目录。 2 | baseDir = '/usr/local/openresty/nginx/conf/waf/' 3 | 4 | local Config = { 5 | -- key是否动态生成,可选static,dynamic,如果选dynamic,下面所有的keySecret不需要更改,如果选static,修改手动修改下面的keySecret 6 | keyDefine = "dynamic", 7 | 8 | -- 被动防御,限制请求模块。根据在一定时间内统计到的请求次数作限制,建议始终开启 9 | -- state : 为此模块的状态,表示开启或关闭,可选值为On或Off; 10 | -- maxReqs,amongTime : 在amongTime秒内允许请求的最大次数maxReqs,如默认的是在10s内最大允许请求50次。 11 | -- urlProtect : 指定限制请求次数的url正则表达式文件,默认值为\.php$,表示只限制php的请求(当然,当urlMatchMode = "uri"时,此正则才能起作用) 12 | limitReqModules = { state = "On" , maxReqs = 4 , amongTime = 10, urlProtect = baseDir.."url-protect/limit.txt" }, 13 | 14 | 15 | -- 主动防御,302响应头跳转模块。利用cc控制端不支持解析响应头的特点,来识别是否为正常用户,当有必要时才建议开启。 16 | -- state : 为此模块的状态,表示开启或关闭,可选值为On或Off; 17 | -- verifyMaxFail amongTime : 因为此模块会发送带有cckey及keyexpire的302响应头,如果访客在amongTime时间内超过verifyMaxFail次没有跳转到302响应头里的url,就会被添加到黑名单,默认值为5次。 18 | -- keySecret : 用于生成token的密码,如果上面的keyDefine为dynamic,就不需要修改 19 | -- urlProtect 同limitReqModules模块中的urlProtect的解释。 20 | redirectModules = { state = "On" ,verifyMaxFail = 5, keySecret = 'yK48J276hg', amongTime = 60 ,urlProtect = baseDir.."url-protect/302.txt"}, 21 | 22 | 23 | -- 主动防御,发送js跳转代码模块。利用cc控制端无法解析js跳转的特点,来识别是否为正常用户,当有必要时才建议开启。 24 | -- state : 为此模块的状态,表示开启或关闭,可选值为On或Off; 25 | -- verifyMaxFail amongTime : 因为此模块会发送带有js跳转代码的响应体,如果访客在amongTime时间内超过verifyMaxFail次没有跳转到js跳转代码里的url,就会被添加到黑名单,默认值为5次。 26 | -- keySecret : 用于生成token的密码,如果上面的keyDefine为dynamic,就不需要修改 27 | -- urlProtect 同limitReqModules模块中的urlProtect的解释。 28 | JsJumpModules = { state = "Off" ,verifyMaxFail = 5, keySecret = 'QSjL6p38h9', amongTime = 60 , urlProtect = baseDir.."url-protect/js.txt"}, 29 | 30 | -- 主动防御,发送cookie验证模块。此模块会向访客发送cookie,然后等待访客返回正确的cookie,此模块利用cc控制端无法支持cookie的特点,来识别cc攻击,当有必要时才建议开启 31 | -- state : 为此模块的状态,表示开启或关闭,可选值为On或Off; 32 | -- verifyMaxFail amongTime : 因为此模块会发送cookie,如果访客在amongTime时间内超过verifyMaxFail次没有返回正确的cookie,就会被添加到黑名单,默认值为5次。 33 | -- keySecret : 用于生成token的密码,如果上面的keyDefine为dynamic,就不需要修改 34 | -- urlProtect 同limitReqModules模块中的urlProtect的解释。 35 | cookieModules = { state = "Off" ,verifyMaxFail = 5, keySecret = 'bGMfY2D5t3', amongTime = 60 , urlProtect = baseDir.."url-protect/cookie.txt"}, 36 | 37 | -- 自动开启主动防御,原理是根据protectPort端口的已连接数超过maxConnection来确定 38 | -- state : 为此模块的状态,表示开启或关闭,可选值为On或Off; 39 | -- interval 间隔30秒检查一次连接数,默认为30秒。 40 | -- protectPort,maxConnection,normalTimes,exceedTimes : enableModule中的模块为关闭状态时,当端口protectPort的连接数连续exceedTimes次超过maxConnection时,开启enableModule中的模块; 41 | -- enableModule中的模块为开启状态时,当端口protectPort的连接数连续normalTimes次低于maxConnection时,关闭enableModule中的模块。 42 | -- ssCommand : 我们是使用ss命令来检查特定端口的已连接的连接数,ss命令比同类的命令netstat快得多。请把ss命令的路径改为自己系统上的路径。 43 | -- enableModules : 自动启动哪个主动防御模块,可选值为redirectModules JsJumpModules cookieModules 44 | autoEnable = { state = "off", protectPort = "80", interval = 30, normalTimes = 3,exceedTimes = 2,maxConnection = 500, ssCommand = "/usr/sbin/ss" ,enableModule = "redirectModules"}, 45 | 46 | -- 用于当输入验证码验证通过时,生成key的密码.如果上面的keyDefine为dynamic,就不需要修改 47 | captchaKey = "K4QEaHjwyF", 48 | 49 | -- ip在黑名单时执行的动作(可选值captcha,forbidden,iptables) 50 | -- 值为captcha时,表示ip在黑名单后返回带有验证码的页面,输入正确的验证码才允许继续访问网站 51 | -- 值为forbidden时,表示ip在黑名单后,服务器会直接断开与用户的连接. 52 | -- 值为iptables时,表示ip在黑名单后,http-guard会用iptables封锁此ip的连接 53 | -- 当值为iptables时,需要为nginx运行用户设置密码及添加到sudo以便能执行iptables命令。假设nginx运行用户为www,设置方法为: 54 | -- 1.设置www密码,命令为passwd www 55 | -- 2.以根用户执行visudo命令,添加www ALL=(root) /sbin/iptables -I INPUT -p tcp -s [0-9.]* --dport 80 -j DROP 56 | -- 3.以根用户执行visudo命令,找到Default requiretty注释,即更改为#Default requiretty,如果找不到此设置,就不需要改。 57 | blockAction = "captcha", 58 | 59 | -- nginx运行用户的sudo密码,blockAction值为iptables需要设置,否则不需要 60 | sudoPass = '', 61 | 62 | -- 表示http-guard封锁ip的时间 63 | blockTime = 600, 64 | 65 | -- JsJumpModules redirectModules cookieModules验证通过后,ip在白名单的时间 66 | whiteTime = 600, 67 | 68 | -- 用于生成token密码的key过期时间 69 | keyExpire = 600, 70 | 71 | -- 匹配url模式,可选值requestUri,uri 72 | -- 值requestUri时,url-protect目录下的正则匹配的是浏览器最初请求的地址且没有被decode,带参数的链接 73 | -- 值为uri时, url-protect目录下的正则匹配的是经过重写过的地址,不带参数,且已经decode. 74 | urlMatchMode = "uri", 75 | 76 | -- 验证码页面路径,一般不需要修改 77 | captchaPage = baseDir.."html/captcha.html", 78 | 79 | -- 输入验证码错误时显示的页面路径,一般不需要修改 80 | reCaptchaPage = baseDir.."html/reCatchaPage.html", 81 | 82 | -- 白名单ip文件,文件内容为正则表达式。 83 | whiteIpModules = { state = "Off", ipList = baseDir.."url-protect/white_ip_list.txt" }, 84 | 85 | -- 如果需要从请求头获取真实ip,此值就需要设置,如x-forwarded-for 86 | -- 当state为on时,此设置才有效 87 | realIpFromHeader = { state = "Off", header = "x-forwarded-for"}, 88 | 89 | -- 指定验证码图片目录,一般不需要修改 90 | captchaDir = baseDir.."captcha/", 91 | 92 | -- 是否开启debug日志 93 | debug = true, 94 | 95 | --日志目录,一般不需要修改.但需要设置logs所有者为nginx运行用户,如nginx运行用户为www,则命令为chown www logs 96 | logPath = baseDir.."logs/", 97 | 98 | --对url进行匹配 99 | uriFilter = {state="On",uriReFile = baseDir.."url-protect/uri.txt"}, 100 | postFilter = {state="On",postReFile = baseDir.."url-protect/post.txt"}, 101 | } 102 | 103 | return Config 104 | -------------------------------------------------------------------------------- /guard.lua: -------------------------------------------------------------------------------- 1 | local Guard = {} 2 | 3 | --debug日志 4 | function Guard:debug(data,ip,reqUri) 5 | local reqUri = ngx.var.request_uri 6 | if _Conf.debug then 7 | local date = os.date("%Y-%m-%d") 8 | local filename = _Conf.logPath.."/debug-"..date..".log" 9 | local file = io.open(filename,"a+") 10 | file:write(os.date('%Y-%m-%d %H:%M:%S').." [DEBUG] "..data.." IP "..ip.." GET "..reqUri.."\n") 11 | file:close() 12 | end 13 | end 14 | 15 | --攻击日志 16 | function Guard:log(data) 17 | local date = os.date("%Y-%m-%d") 18 | local filename = _Conf.logPath.."/attack-"..date..".log" 19 | local file = io.open(filename,"a+") 20 | file:write(os.date('%Y-%m-%d %H:%M:%S').." [WARNING] "..data.."\n") 21 | file:close() 22 | end 23 | 24 | --获取真实ip 25 | function Guard:getRealIp(remoteIp,headers) 26 | if _Conf.realIpFromHeaderIsOn then 27 | readIp = headers[_Conf.realIpFromHeader.header] 28 | if readIp then 29 | self:debug("[getRealIp] realIpFromHeader is on.return ip "..readIp,remoteIp,"") 30 | return headers[_Conf.realIpFromHeader.header] 31 | else 32 | return remoteIp 33 | end 34 | else 35 | return remoteIp 36 | end 37 | end 38 | 39 | --白名单模块 40 | function Guard:ipInWhiteList(ip) 41 | if _Conf.whiteIpModulesIsOn then --判断是否开启白名单模块 42 | self:debug("[ipInWhiteList] whiteIpModules is on.",ip,"") 43 | 44 | if ngx.re.match(ip, _Conf.whiteIpList) then --匹配白名单列表 45 | self:debug("[ipInWhiteList] ip "..ip.. " match white list ".._Conf.whiteIpList,ip,"") 46 | return true 47 | else 48 | return false 49 | end 50 | end 51 | end 52 | 53 | --黑名单模块 54 | function Guard:blackListModules(ip,reqUri) 55 | local blackKey = ip.."black" 56 | if _Conf.dict:get(blackKey) then --判断ip是否存在黑名单字典 57 | self:debug("[blackListModules] ip "..ip.." in blacklist",ip,reqUri) 58 | self:takeAction(ip,reqUri) --存在则执行相应动作 59 | end 60 | end 61 | 62 | --限制请求速率模块 63 | function Guard:limitReqModules(ip,reqUri,address) 64 | if ngx.re.match(address,_Conf.limitUrlProtect,"i") then 65 | self:debug("[limitReqModules] address "..address.." match reg ".._Conf.limitUrlProtect,ip,reqUri) 66 | local blackKey = ip.."black" 67 | local limitReqKey = ip.."limitreqkey" --定义limitreq key 68 | local reqTimes = _Conf.dict:get(limitReqKey) --获取此ip请求的次数 69 | 70 | --增加一次请求记录 71 | if reqTimes then 72 | _Conf.dict:incr(limitReqKey, 1) 73 | else 74 | _Conf.dict:set(limitReqKey, 1, _Conf.limitReqModules.amongTime) 75 | reqTimes = 0 76 | end 77 | 78 | local newReqTimes = reqTimes + 1 79 | self:debug("[limitReqModules] newReqTimes "..newReqTimes,ip,reqUri) 80 | 81 | --判断请求数是否大于阀值,大于则添加黑名单 82 | if newReqTimes > _Conf.limitReqModules.maxReqs then --判断是否请求数大于阀值 83 | self:debug("[limitReqModules] ip "..ip.. " request exceed ".._Conf.limitReqModules.maxReqs,ip,reqUri) 84 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 85 | self:log("[limitReqModules] IP "..ip.." visit "..newReqTimes.." times,block it.") 86 | end 87 | 88 | end 89 | end 90 | 91 | --302转向模块 92 | function Guard:redirectModules(ip,reqUri,address) 93 | if ngx.re.match(address,_Conf.redirectUrlProtect,"i") then 94 | self:debug("[redirectModules] address "..address.." match reg ".._Conf.redirectUrlProtect,ip,reqUri) 95 | local whiteKey = ip.."white302" 96 | local inWhiteList = _Conf.dict:get(whiteKey) 97 | 98 | if inWhiteList then --如果在白名单 99 | self:debug("[redirectModules] in white ip list",ip,reqUri) 100 | return 101 | else 102 | --如果不在白名单,再检测是否有cookie凭证 103 | local now = ngx.time() --当前时间戳 104 | local challengeTimesKey = table.concat({ip,"challenge302"}) 105 | local challengeTimesValue = _Conf.dict:get(challengeTimesKey) 106 | local blackKey = ip.."black" 107 | local cookie_key = ngx.var["cookie_key302"] --获取cookie密钥 108 | local cookie_expire = ngx.var["cookie_expire302"] --获取cookie密钥过期时间 109 | 110 | if cookie_key and cookie_expire then 111 | local key_make = ngx.md5(table.concat({ip,_Conf.redirectModules.keySecret,cookie_expire})) 112 | local key_make = string.sub(key_make,"1","10") 113 | --判断cookie是否有效 114 | if tonumber(cookie_expire) > now and cookie_key == key_make then 115 | self:debug("[redirectModules] cookie key is valid.",ip,reqUri) 116 | if challengeTimesValue then 117 | _Conf.dict:delete(challengeTimesKey) --删除验证失败计数器 118 | end 119 | _Conf.dict:set(whiteKey,0,_Conf.whiteTime) --添加到白名单 120 | return 121 | else 122 | self:debug("[redirectModules] cookie key is invalid.",ip,reqUri) 123 | local expire = now + _Conf.keyExpire 124 | local key_new = ngx.md5(table.concat({ip,_Conf.redirectModules.keySecret,expire})) 125 | local key_new = string.sub(key_new,"1","10") 126 | --定义转向的url 127 | local newUrl = '' 128 | local newReqUri = ngx.re.match(reqUri, "(.*?)\\?(.+)") 129 | if newReqUri then 130 | local reqUriNoneArgs = newReqUri[1] 131 | local args = newReqUri[2] 132 | --删除cckey和keyexpire 133 | local newArgs = ngx.re.gsub(args, "[&?]?key302=[^&]+&?|expire302=[^&]+&?", "", "i") 134 | if newArgs == "" then 135 | newUrl = table.concat({reqUriNoneArgs,"?key302=",key_new,"&expire302=",expire}) 136 | else 137 | newUrl = table.concat({reqUriNoneArgs,"?",newArgs,"&key302=",key_new,"&expire302=",expire}) 138 | end 139 | else 140 | newUrl = table.concat({reqUri,"?key302=",key_new,"&expire302=",expire}) 141 | 142 | end 143 | 144 | --验证失败次数加1 145 | if challengeTimesValue then 146 | _Conf.dict:incr(challengeTimesKey,1) 147 | if challengeTimesValue + 1> _Conf.redirectModules.verifyMaxFail then 148 | self:debug("[redirectModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 149 | self:log("[redirectModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.") 150 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 151 | end 152 | else 153 | _Conf.dict:set(challengeTimesKey,1,_Conf.redirectModules.amongTime) 154 | end 155 | 156 | --删除cookie 157 | ngx.header['Set-Cookie'] = {"key302=; path=/", "expire302=; expires=Sat, 01-Jan-2000 00:00:00 GMT; path=/"} 158 | return ngx.redirect(newUrl, 302) --发送302转向 159 | end 160 | else 161 | --如果没有找到cookie,则检测是否带cckey参数 162 | local ccKeyValue = ngx.re.match(reqUri, "key302=([^&]+)","i") 163 | local expire = ngx.re.match(reqUri, "expire302=([^&]+)","i") 164 | 165 | if ccKeyValue and expire then --是否有cckey和keyexpire参数 166 | local ccKeyValue = ccKeyValue[1] 167 | local expire = expire[1] 168 | local key_make = ngx.md5(table.concat({ip,_Conf.redirectModules.keySecret,expire})) 169 | local key_make = string.sub(key_make,"1","10") 170 | self:debug("[redirectModules] ccKeyValue "..ccKeyValue,ip,reqUri) 171 | self:debug("[redirectModules] expire "..expire,ip,reqUri) 172 | self:debug("[redirectModules] key_make "..key_make,ip,reqUri) 173 | self:debug("[redirectModules] ccKeyValue "..ccKeyValue,ip,reqUri) 174 | if key_make == ccKeyValue and now < tonumber(expire) then--判断传过来的cckey参数值是否等于字典记录的值,且没有过期 175 | self:debug("[redirectModules] ip "..ip.." arg key302 "..ccKeyValue.." is valid.add ip to write list.",ip,reqUri) 176 | 177 | if challengeTimesValue then 178 | _Conf.dict:delete(challengeTimesKey) --删除验证失败计数器 179 | end 180 | _Conf.dict:set(whiteKey,0,_Conf.whiteTime) --添加到白名单 181 | ngx.header['Set-Cookie'] = {"key302="..key_make.."; path=/", "expire302="..expire.."; path=/"} --发送cookie凭证 182 | return 183 | else --如果不相等,则再发送302转向 184 | self:debug("[redirectModules] ip "..ip.." arg key302 is invalid.",ip,reqUri) 185 | local expire = now + _Conf.keyExpire 186 | local key_new = ngx.md5(table.concat({ip,_Conf.redirectModules.keySecret,expire})) 187 | local key_new = string.sub(key_new,"1","10") 188 | 189 | --验证失败次数加1 190 | if challengeTimesValue then 191 | _Conf.dict:incr(challengeTimesKey,1) 192 | if challengeTimesValue + 1 > _Conf.redirectModules.verifyMaxFail then 193 | self:debug("[redirectModules] client "..ip.." challenge 302key failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 194 | self:log("[redirectModules] client "..ip.." challenge 302key failed "..challengeTimesValue.." times,add to blacklist.") 195 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 196 | end 197 | else 198 | _Conf.dict:set(challengeTimesKey,1,_Conf.redirectModules.amongTime) 199 | end 200 | --定义转向的url 201 | local newUrl = '' 202 | local newReqUri = ngx.re.match(reqUri, "(.*?)\\?(.+)") 203 | if newReqUri then 204 | local reqUriNoneArgs = newReqUri[1] 205 | local args = newReqUri[2] 206 | --删除cckey和keyexpire 207 | local newArgs = ngx.re.gsub(args, "[&?]?key302=[^&]+&?|expire302=[^&]+&?", "", "i") 208 | if newArgs == "" then 209 | newUrl = table.concat({reqUriNoneArgs,"?key302=",key_new,"&expire302=",expire}) 210 | else 211 | newUrl = table.concat({reqUriNoneArgs,"?",newArgs,"&key302=",key_new,"&expire302=",expire}) 212 | end 213 | else 214 | newUrl = table.concat({reqUri,"?key302=",key_new,"&expire302=",expire}) 215 | 216 | end 217 | 218 | return ngx.redirect(newUrl, 302) --发送302转向 219 | end 220 | else 221 | --验证失败次数加1 222 | if challengeTimesValue then 223 | _Conf.dict:incr(challengeTimesKey,1) 224 | if challengeTimesValue +1 > _Conf.redirectModules.verifyMaxFail then 225 | self:debug("[redirectModules] client "..ip.." challenge 302key failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 226 | self:log("[redirectModules] client "..ip.." challenge 302key failed "..challengeTimesValue.." times,add to blacklist.") 227 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 228 | end 229 | else 230 | _Conf.dict:set(challengeTimesKey,1,_Conf.redirectModules.amongTime) 231 | end 232 | 233 | local expire = now + _Conf.keyExpire 234 | local key_new = ngx.md5(table.concat({ip,_Conf.redirectModules.keySecret,expire})) 235 | local key_new = string.sub(key_new,"1","10") 236 | 237 | --定义转向的url 238 | local newUrl = '' 239 | local newReqUri = ngx.re.match(reqUri, "(.*?)\\?(.+)") 240 | if newReqUri then 241 | local reqUriNoneArgs = newReqUri[1] 242 | local args = newReqUri[2] 243 | --删除cckey和keyexpire 244 | local newArgs = ngx.re.gsub(args, "[&?]?key302=[^&]+&?|expire302=[^&]+&?", "", "i") 245 | if newArgs == "" then 246 | newUrl = table.concat({reqUriNoneArgs,"?key302=",key_new,"&expire302=",expire}) 247 | else 248 | newUrl = table.concat({reqUriNoneArgs,"?",newArgs,"&key302=",key_new,"&expire302=",expire}) 249 | end 250 | else 251 | newUrl = table.concat({reqUri,"?key302=",key_new,"&expire302=",expire}) 252 | 253 | end 254 | 255 | return ngx.redirect(newUrl, 302) --发送302转向 256 | end 257 | end 258 | end 259 | end 260 | end 261 | 262 | --js跳转模块 263 | function Guard:JsJumpModules(ip,reqUri,address) 264 | if ngx.re.match(address,_Conf.JsJumpUrlProtect,"i") then 265 | self:debug("[JsJumpModules] address "..address.." match reg ".._Conf.JsJumpUrlProtect,ip,reqUri) 266 | local whiteKey = ip.."whitejs" 267 | local inWhiteList = _Conf.dict:get(whiteKey) 268 | 269 | if inWhiteList then --如果在白名单 270 | self:debug("[JsJumpModules] in white ip list",ip,reqUri) 271 | return 272 | else 273 | --如果不在白名单,检测是否有cookie凭证 274 | local cookie_key = ngx.var["cookie_keyjs"] --获取cookie密钥 275 | local cookie_expire = ngx.var["cookie_expirejs"] --获取cookie密钥过期时间 276 | local now = ngx.time() --当前时间戳 277 | local challengeTimesKey = table.concat({ip,"challengejs"}) 278 | local challengeTimesValue = _Conf.dict:get(challengeTimesKey) 279 | local blackKey = ip.."black" 280 | local cookie_key = ngx.var["cookie_keyjs"] --获取cookie密钥 281 | local cookie_expire = ngx.var["cookie_expirejs"] --获取cookie密钥过期时间 282 | 283 | if cookie_key and cookie_expire then 284 | local key_make = ngx.md5(table.concat({ip,_Conf.JsJumpModules.keySecret,cookie_expire})) 285 | local key_make = string.sub(key_make,"1","10") 286 | if tonumber(cookie_expire) > now and cookie_key == key_make then 287 | if challengeTimesValue then 288 | _Conf.dict:delete(challengeTimesKey) --删除验证失败计数器 289 | end 290 | self:debug("[JsJumpModules] cookie key is valid.",ip,reqUri) 291 | _Conf.dict:set(whiteKey,0,_Conf.whiteTime) --添加ip到白名单 292 | return 293 | else 294 | --验证失败次数加1 295 | if challengeTimesValue then 296 | _Conf.dict:incr(challengeTimesKey,1) 297 | if challengeTimesValue +1 > _Conf.JsJumpModules.verifyMaxFail then 298 | self:debug("[JsJumpModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 299 | self:log("[JsJumpModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.") 300 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 301 | end 302 | else 303 | _Conf.dict:set(challengeTimesKey,1,_Conf.JsJumpModules.amongTime) 304 | end 305 | 306 | self:debug("[JsJumpModules] cookie key is invalid.",ip,reqUri) 307 | local expire = now + _Conf.keyExpire 308 | local key_new = ngx.md5(table.concat({ip,_Conf.JsJumpModules.keySecret,expire})) 309 | local key_new = string.sub(key_new,"1","10") 310 | 311 | --定义转向的url 312 | local newUrl = '' 313 | local newReqUri = ngx.re.match(reqUri, "(.*?)\\?(.+)") 314 | if newReqUri then 315 | local reqUriNoneArgs = newReqUri[1] 316 | local args = newReqUri[2] 317 | --删除cckey和keyexpire 318 | local newArgs = ngx.re.gsub(args, "[&?]?keyjs=[^&]+&?|expirejs=[^&]+&?", "", "i") 319 | if newArgs == "" then 320 | newUrl = table.concat({reqUriNoneArgs,"?keyjs=",key_new,"&expirejs=",expire}) 321 | else 322 | newUrl = table.concat({reqUriNoneArgs,"?",newArgs,"&keyjs=",key_new,"&expirejs=",expire}) 323 | end 324 | else 325 | newUrl = table.concat({reqUri,"?keyjs=",key_new,"&expirejs=",expire}) 326 | 327 | end 328 | 329 | local jsJumpCode=table.concat({""}) --定义js跳转代码 330 | ngx.header.content_type = "text/html" 331 | --删除cookie 332 | ngx.header['Set-Cookie'] = {"keyjs=; path=/", "expirejs=; expires=Sat, 01-Jan-2000 00:00:00 GMT; path=/"} 333 | ngx.print(jsJumpCode) 334 | ngx.exit(200) 335 | end 336 | else 337 | --如果没有cookie凭证,检测url是否带有cckey参数 338 | local ccKeyValue = ngx.re.match(reqUri, "keyjs=([^&]+)","i") 339 | local expire = ngx.re.match(reqUri, "expirejs=([^&]+)","i") 340 | 341 | if ccKeyValue and expire then 342 | local ccKeyValue = ccKeyValue[1] 343 | local expire = expire[1] 344 | 345 | local key_make = ngx.md5(table.concat({ip,_Conf.JsJumpModules.keySecret,expire})) 346 | local key_make = string.sub(key_make,"1","10") 347 | 348 | if key_make == ccKeyValue and now < tonumber(expire) then--判断传过来的cckey参数值是否等于字典记录的值,且没有过期 349 | self:debug("[JsJumpModules] ip "..ip.." arg keyjs "..ccKeyValue.." is valid.add ip to white list.",ip,reqUri) 350 | if challengeTimesValue then 351 | _Conf.dict:delete(challengeTimesKey) --删除验证失败计数器 352 | end 353 | _Conf.dict:set(whiteKey,0,_Conf.whiteTime) --添加ip到白名单 354 | ngx.header['Set-Cookie'] = {"keyjs="..key_make.."; path=/", "expirejs="..expire.."; path=/"} --发送cookie凭证 355 | return 356 | else --如果不相等,则再发送302转向 357 | --验证失败次数加1 358 | if challengeTimesValue then 359 | _Conf.dict:incr(challengeTimesKey,1) 360 | if challengeTimesValue + 1 > _Conf.JsJumpModules.verifyMaxFail then 361 | self:debug("[JsJumpModules] client "..ip.." challenge jskey failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 362 | self:log("[JsJumpModules] client "..ip.." challenge jskey failed "..challengeTimesValue.." times,add to blacklist.") 363 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 364 | end 365 | else 366 | _Conf.dict:set(challengeTimesKey,1,_Conf.JsJumpModules.amongTime) 367 | end 368 | 369 | self:debug("[JsJumpModules] ip "..ip.." arg keyjs is invalid.",ip,reqUri) 370 | local expire = now + _Conf.keyExpire 371 | local key_new = ngx.md5(table.concat({ip,_Conf.JsJumpModules.keySecret,expire})) 372 | local key_new = string.sub(key_new,"1","10") 373 | --定义转向的url 374 | local newUrl = '' 375 | local newReqUri = ngx.re.match(reqUri, "(.*?)\\?(.+)") 376 | if newReqUri then 377 | local reqUriNoneArgs = newReqUri[1] 378 | local args = newReqUri[2] 379 | --删除cckey和keyexpire 380 | local newArgs = ngx.re.gsub(args, "[&?]?keyjs=[^&]+&?|expirejs=[^&]+&?", "", "i") 381 | if newArgs == "" then 382 | newUrl = table.concat({reqUriNoneArgs,"?keyjs=",key_new,"&expirejs=",expire}) 383 | else 384 | newUrl = table.concat({reqUriNoneArgs,"?",newArgs,"&keyjs=",key_new,"&expirejs=",expire}) 385 | end 386 | else 387 | newUrl = table.concat({reqUri,"?keyjs=",key_new,"&expirejs=",expire}) 388 | 389 | end 390 | local jsJumpCode=table.concat({""}) --定义js跳转代码 391 | ngx.header.content_type = "text/html" 392 | ngx.print(jsJumpCode) 393 | ngx.exit(200) 394 | end 395 | else 396 | --验证失败次数加1 397 | if challengeTimesValue then 398 | _Conf.dict:incr(challengeTimesKey,1) 399 | if challengeTimesValue + 1 > _Conf.JsJumpModules.verifyMaxFail then 400 | self:debug("[JsJumpModules] client "..ip.." challenge jskey failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 401 | self:log("[JsJumpModules] client "..ip.." challenge jskey failed "..challengeTimesValue.." times,add to blacklist.") 402 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 403 | end 404 | else 405 | _Conf.dict:set(challengeTimesKey,1,_Conf.JsJumpModules.amongTime) 406 | end 407 | 408 | --定义转向的url 409 | local expire = now + _Conf.keyExpire 410 | local key_new = ngx.md5(table.concat({ip,_Conf.JsJumpModules.keySecret,expire})) 411 | local key_new = string.sub(key_new,"1","10") 412 | 413 | --定义转向的url 414 | local newUrl = '' 415 | local newReqUri = ngx.re.match(reqUri, "(.*?)\\?(.+)") 416 | if newReqUri then 417 | local reqUriNoneArgs = newReqUri[1] 418 | local args = newReqUri[2] 419 | --删除cckey和keyexpire 420 | local newArgs = ngx.re.gsub(args, "[&?]?keyjs=[^&]+&?|expirejs=[^&]+&?", "", "i") 421 | if newArgs == "" then 422 | newUrl = table.concat({reqUriNoneArgs,"?keyjs=",key_new,"&expirejs=",expire}) 423 | else 424 | newUrl = table.concat({reqUriNoneArgs,"?",newArgs,"&keyjs=",key_new,"&expirejs=",expire}) 425 | end 426 | else 427 | newUrl = table.concat({reqUri,"?keyjs=",key_new,"&expirejs=",expire}) 428 | 429 | end 430 | 431 | local jsJumpCode=table.concat({""}) --定义js跳转代码 432 | ngx.header.content_type = "text/html" 433 | ngx.print(jsJumpCode) 434 | ngx.exit(200) 435 | end 436 | end 437 | end 438 | end 439 | end 440 | 441 | --cookie验证模块 442 | function Guard:cookieModules(ip,reqUri,address) 443 | if ngx.re.match(address,_Conf.cookieUrlProtect,"i") then 444 | self:debug("[cookieModules] address "..address.." match reg ".._Conf.cookieUrlProtect,ip,reqUri) 445 | local whiteKey = ip.."whitecookie" 446 | local inWhiteList = _Conf.dict:get(whiteKey) 447 | 448 | if inWhiteList then --如果在白名单 449 | self:debug("[cookieModules] in white ip list.",ip,reqUri) 450 | return 451 | else 452 | local cookie_key = ngx.var["cookie_keycookie"] --获取cookie密钥 453 | local cookie_expire = ngx.var["cookie_expirecookie"] --获取cookie密钥过期时间 454 | local now = ngx.time() --当前时间戳 455 | local challengeTimesKey = table.concat({ip,"challengecookie"}) 456 | local challengeTimesValue = _Conf.dict:get(challengeTimesKey) 457 | local blackKey = ip.."black" 458 | 459 | if cookie_key and cookie_expire then --判断是否有收到cookie 460 | local key_make = ngx.md5(table.concat({ip,_Conf.cookieModules.keySecret,cookie_expire})) 461 | local key_make = string.sub(key_make,"1","10") 462 | if tonumber(cookie_expire) > now and cookie_key == key_make then 463 | if challengeTimesValue then 464 | _Conf.dict:delete(challengeTimesKey) --删除验证失败计数器 465 | end 466 | self:debug("[cookieModules] cookie key is valid.add to white ip list",ip,reqUri) 467 | _Conf.dict:set(whiteKey,0,_Conf.whiteTime) --添加ip到白名单 468 | return 469 | else 470 | self:debug("[cookieModules] cookie key is invalid",ip,reqUri) 471 | --验证失败次数加1 472 | if challengeTimesValue then 473 | _Conf.dict:incr(challengeTimesKey,1) 474 | if challengeTimesValue +1 > _Conf.cookieModules.verifyMaxFail then 475 | self:debug("[cookieModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 476 | self:log("[cookieModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.") 477 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 478 | end 479 | else 480 | _Conf.dict:set(challengeTimesKey,1,_Conf.cookieModules.amongTime) 481 | end 482 | 483 | ngx.header['Set-Cookie'] = {"keycookie=; path=/", "expirecookie=; expires=Sat, 01-Jan-2000 00:00:00 GMT; path=/"} --删除cookie 484 | end 485 | else --找不到cookie 486 | self:debug("[cookieModules] cookie not found.",ip,reqUri) 487 | --验证失败次数加1 488 | if challengeTimesValue then 489 | _Conf.dict:incr(challengeTimesKey,1) 490 | if challengeTimesValue +1 > _Conf.cookieModules.verifyMaxFail then 491 | self:debug("[cookieModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.",ip,reqUri) 492 | self:log("[cookieModules] client "..ip.." challenge cookie failed "..challengeTimesValue.." times,add to blacklist.") 493 | _Conf.dict:set(blackKey,0,_Conf.blockTime) --添加此ip到黑名单 494 | end 495 | else 496 | _Conf.dict:set(challengeTimesKey,1,_Conf.cookieModules.amongTime) 497 | end 498 | 499 | local expire = now + _Conf.keyExpire 500 | local key_new = ngx.md5(table.concat({ip,_Conf.cookieModules.keySecret,expire})) 501 | local key_new = string.sub(key_new,"1","10") 502 | 503 | self:debug("[cookieModules] send cookie to client.",ip,reqUri) 504 | ngx.header['Set-Cookie'] = {"keycookie="..key_new.."; path=/", "expirecookie="..expire.."; path=/"} --发送cookie凭证 505 | end 506 | end 507 | end 508 | end 509 | --url匹配处理 510 | function Guard:uriFilterModule(ip,reqUri) 511 | local m,err = ngx.re.match(reqUri,_Conf.uriProtect,"i") 512 | if m then 513 | ngx.exit(403) 514 | end 515 | end 516 | --post body 过滤操作 517 | function Guard:postFilterModule(ip,reqUri) 518 | ngx.req.read_body() 519 | local args, err = ngx.req.get_post_args() 520 | ngx.header.content_type = "text/html" 521 | if not args then 522 | ngx.say("failed to get post args: ", err) 523 | return 524 | end 525 | for key, val in pairs(args) do 526 | if type(val) == "table" then 527 | val=table.concat(val, ", ") 528 | --ngx.say(key, ": ", table.concat(val, ", ")) 529 | --if ngx.re.match(value,_Conf.postProtect,'i')then 530 | -- ngx.exit(403) 531 | --end 532 | end 533 | --else 534 | if ngx.re.match(val,_Conf.postProtect,'i') then 535 | --ngx.say(key, ": ", val) 536 | ngx.exit(403) 537 | --else 538 | -- ngx.say(key, ": ", 'aa') 539 | -- ngx.exit(200) 540 | end 541 | end 542 | end 543 | 544 | 545 | 546 | --获取验证码 547 | function Guard:getCaptcha() 548 | --math.randomseed(ngx.now()) --随机种子 549 | local random = math.random(1,10000) --生成1-10000之前的随机数 550 | self:debug("[getCaptcha] get random num "..random,"","") 551 | local captchaValue = _Conf.dict_captcha:get(random) --取得字典中的验证码 552 | self:debug("[getCaptcha] get captchaValue "..captchaValue,"","") 553 | local captchaImg = _Conf.dict_captcha:get(captchaValue) --取得验证码对应的图片 554 | --返回图片 555 | ngx.header.content_type = "image/jpeg" 556 | ngx.header['Set-Cookie'] = table.concat({"captchaNum=",random,"; path=/"}) 557 | ngx.print(captchaImg) 558 | ngx.exit(200) 559 | end 560 | 561 | --验证验证码 562 | function Guard:verifyCaptcha(ip) 563 | local limitReqKey = ip.."limitreqkey" 564 | ngx.req.read_body() 565 | local captchaNum = ngx.var["cookie_captchaNum"] --获取cookie captchaNum值 566 | local preurl = ngx.var["cookie_preurl"] --获取上次访问url 567 | self:debug("[verifyCaptcha] get cookie captchaNum "..captchaNum,ip,"") 568 | local args = ngx.req.get_post_args() --获取post参数 569 | local postValue = args["response"] --获取post value参数 570 | postValue = string.lower(postValue) 571 | self:debug("[verifyCaptcha] get post arg response "..postValue,ip,"") 572 | local captchaValue = _Conf.dict_captcha:get(captchaNum) --从字典获取post value对应的验证码值 573 | if captchaValue == postValue then --比较验证码是否相等 574 | self:debug("[verifyCaptcha] captcha is valid.delete from blacklist",ip,"") 575 | _Conf.dict:delete(ip.."black") --从黑名单删除 576 | self:debug("[--------------------------------------------------------] captcha is valid.delete from blacklist",_Conf.limitReqModules.amongTime,"") 577 | --_Conf.dict:delete(ip.."limitreqkey") --访问记录删除 578 | _Conf.dict:delete(limitReqKey) 579 | _Conf.dict:set(limitReqKey, 1, _Conf.limitReqModules.amongTime)--重新计数 580 | local expire = ngx.time() + _Conf.keyExpire 581 | local captchaKey = ngx.md5(table.concat({ip,_Conf.captchaKey,expire})) 582 | local captchaKey = string.sub(captchaKey,"1","10") 583 | self:debug("[verifyCaptcha] expire "..expire,ip,"") 584 | self:debug("[verifyCaptcha] captchaKey "..captchaKey,ip,"") 585 | ngx.header['Set-Cookie'] = {"captchaKey="..captchaKey.."; path=/", "captchaExpire="..expire.."; path=/"} 586 | return ngx.redirect(preurl) --返回上次访问url 587 | else 588 | --重新发送验证码页面 589 | self:debug("[verifyCaptcha] captcha invalid",ip,"") 590 | ngx.header.content_type = "text/html" 591 | ngx.print(_Conf.reCaptchaPage) 592 | ngx.exit(200) 593 | end 594 | end 595 | 596 | --拒绝访问动作 597 | function Guard:forbiddenAction() 598 | ngx.header.content_type = "text/html" 599 | ngx.exit(444) 600 | end 601 | 602 | --展示验证码页面动作 603 | function Guard:captchaAction(reqUri) 604 | local reqUri=ngx.var.request_uri 605 | ngx.header.content_type = "text/html" 606 | ngx.header['Set-Cookie'] = table.concat({"preurl=",reqUri,"; path=/"}) 607 | ngx.print(_Conf.captchaPage) 608 | ngx.exit(200) 609 | end 610 | 611 | --执行相应动作 612 | function Guard:takeAction(ip,reqUri) 613 | if _Conf.captchaAction then 614 | local cookie_key = ngx.var["cookie_captchaKey"] --获取cookie captcha密钥 615 | local cookie_expire = ngx.var["cookie_captchaExpire"] --获取cookie captcha过期时间 616 | if cookie_expire and cookie_key then 617 | local now = ngx.time() 618 | local key_make = ngx.md5(table.concat({ip,_Conf.captchaKey,cookie_expire})) 619 | local key_make = string.sub(key_make,"1","10") 620 | self:debug("[takeAction] cookie_expire "..cookie_expire,ip,reqUri) 621 | self:debug("[takeAction] cookie_key "..cookie_key,ip,reqUri) 622 | self:debug("[takeAction] now "..now,ip,reqUri) 623 | self:debug("[takeAction] key_make "..key_make,ip,reqUri) 624 | self:debug("[takeAction] key_make "..now,ip,now) 625 | if tonumber(cookie_expire) > now and cookie_key == key_make then 626 | self:debug("[takeAction] cookie key is valid.",ip,reqUri) 627 | --self:captchaAction(reqUri) 628 | return 629 | else 630 | self:debug("[takeAction] cookie key is invalid",ip,reqUri) 631 | self:captchaAction(reqUri) 632 | end 633 | else 634 | self:debug("[takeAction] return captchaAction",ip,reqUri) 635 | self:captchaAction(reqUri) 636 | end 637 | elseif _Conf.forbiddenAction then 638 | self:debug("[takeAction] return forbiddenAction",ip,reqUri) 639 | self:forbiddenAction() 640 | 641 | elseif _Conf.iptablesAction then 642 | ngx.thread.spawn(Guard.addToIptables,Guard,ip) 643 | end 644 | end 645 | 646 | --添加进iptables drop表 647 | function Guard:addToIptables(ip) 648 | local cmd = "echo ".._Conf.sudoPass.." | sudo -S /sbin/iptables -I INPUT -p tcp -s "..ip.." --dport 80 -j DROP" 649 | os.execute(cmd) 650 | end 651 | 652 | --自动开启或关闭防cc功能 653 | function Guard:autoSwitch() 654 | if not _Conf.dict_captcha:get("monitor") then 655 | _Conf.dict_captcha:set("monitor",0,_Conf.autoEnable.interval) 656 | local f=io.popen(_Conf.autoEnable.ssCommand.." -tan state established '( sport = :".._Conf.autoEnable.protectPort.." or dport = :".._Conf.autoEnable.protectPort.." )' | wc -l") 657 | local result=f:read("*all") 658 | local connection=tonumber(result) 659 | Guard:debug("[autoSwitch] current connection for port ".._Conf.autoEnable.protectPort.." is "..connection,"","") 660 | if _Conf.autoEnable.enableModule == "redirectModules" then 661 | local redirectOn = _Conf.dict_captcha:get("redirectOn") 662 | if redirectOn == 1 then 663 | _Conf.dict_captcha:set("exceedCount",0) --超限次数清0 664 | --如果当前连接在最大连接之下,为正常次数加1 665 | if connection < _Conf.autoEnable.maxConnection then 666 | _Conf.dict_captcha:incr("normalCount",1) 667 | end 668 | 669 | --如果正常次数大于_Conf.autoEnable.normalTimes,关闭redirectModules 670 | local normalCount = _Conf.dict_captcha:get("normalCount") 671 | if normalCount > _Conf.autoEnable.normalTimes then 672 | Guard:log("[autoSwitch] turn redirectModules off.") 673 | _Conf.dict_captcha:set("redirectOn",0) 674 | end 675 | else 676 | _Conf.dict_captcha:set("normalCount",0) --正常次数清0 677 | --如果当前连接在最大连接之上,为超限次数加1 678 | if connection > _Conf.autoEnable.maxConnection then 679 | _Conf.dict_captcha:incr("exceedCount",1) 680 | end 681 | 682 | --如果超限次数大于_Conf.autoEnable.exceedTimes,开启redirectModules 683 | local exceedCount = _Conf.dict_captcha:get("exceedCount") 684 | if exceedCount > _Conf.autoEnable.exceedTimes then 685 | Guard:log("[autoSwitch] turn redirectModules on.") 686 | _Conf.dict_captcha:set("redirectOn",1) 687 | end 688 | end 689 | 690 | elseif _Conf.autoEnable.enableModule == "JsJumpModules" then 691 | local jsOn = _Conf.dict_captcha:get("jsOn") 692 | if jsOn == 1 then 693 | _Conf.dict_captcha:set("exceedCount",0) --超限次数清0 694 | --如果当前连接在最大连接之下,为正常次数加1 695 | if connection < _Conf.autoEnable.maxConnection then 696 | _Conf.dict_captcha:incr("normalCount",1) 697 | end 698 | 699 | --如果正常次数大于_Conf.autoEnable.normalTimes,关闭JsJumpModules 700 | local normalCount = _Conf.dict_captcha:get("normalCount") 701 | if normalCount > _Conf.autoEnable.normalTimes then 702 | Guard:log("[autoSwitch] turn JsJumpModules off.") 703 | _Conf.dict_captcha:set("jsOn",0) 704 | end 705 | else 706 | _Conf.dict_captcha:set("normalCount",0) --正常次数清0 707 | --如果当前连接在最大连接之上,为超限次数加1 708 | if connection > _Conf.autoEnable.maxConnection then 709 | _Conf.dict_captcha:incr("exceedCount",1) 710 | end 711 | 712 | --如果超限次数大于_Conf.autoEnable.exceedTimes,开启JsJumpModules 713 | local exceedCount = _Conf.dict_captcha:get("exceedCount") 714 | if exceedCount > _Conf.autoEnable.exceedTimes then 715 | Guard:log("[autoSwitch] turn JsJumpModules on.") 716 | _Conf.dict_captcha:set("jsOn",1) 717 | end 718 | end 719 | 720 | elseif _Conf.autoEnable.enableModule == "cookieModules" then 721 | local cookieOn = _Conf.dict_captcha:get("cookieOn") 722 | if cookieOn == 1 then 723 | _Conf.dict_captcha:set("exceedCount",0) --超限次数清0 724 | --如果当前连接在最大连接之下,为正常次数加1 725 | if connection < _Conf.autoEnable.maxConnection then 726 | _Conf.dict_captcha:incr("normalCount",1) 727 | end 728 | 729 | --如果正常次数大于_Conf.autoEnable.normalTimes,关闭cookieModules 730 | local normalCount = _Conf.dict_captcha:get("normalCount") 731 | if normalCount > _Conf.autoEnable.normalTimes then 732 | Guard:log("[autoSwitch] turn cookieModules off.") 733 | _Conf.dict_captcha:set("cookieOn",0) 734 | end 735 | else 736 | _Conf.dict_captcha:set("normalCount",0) --正常次数清0 737 | --如果当前连接在最大连接之上,为超限次数加1 738 | if connection > _Conf.autoEnable.maxConnection then 739 | _Conf.dict_captcha:incr("exceedCount",1) 740 | end 741 | 742 | --如果超限次数大于_Conf.autoEnable.exceedTimes,开启cookieModules 743 | local exceedCount = _Conf.dict_captcha:get("exceedCount") 744 | if exceedCount > _Conf.autoEnable.exceedTimes then 745 | Guard:log("[autoSwitch] turn cookieModules on.") 746 | _Conf.dict_captcha:set("cookieOn",1) 747 | end 748 | end 749 | end 750 | end 751 | end 752 | 753 | return Guard 754 | -------------------------------------------------------------------------------- /html/captcha.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。
18 |要继续访问网页,请输入下面所示字符:
19 | 22 |您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。
18 |要继续访问网页,请输入下面所示字符:
19 |验证码输入错误,请重新输入
20 | 23 |