2019-07-17
发表者 Venus
基于openresty实现防CC攻击脚本已关闭评论
ngx.header.content_type="text/html;charset=utf8"
-- redis中key失效时间,做为单位时间内访问次数统计。
timeout = 60
-- 超过阀值,阻断时间,单位秒(等于将key失效时间延长)
blocktime = 120
-- 计数阀值,单位时间内请求次数限制
countper = 10
-- 配置token字段(唯一的字段,可以是其他字符。)从哪里获取。1 header, 2 post参数(需要 MIME type application/x-www-form-urlencoded)
tokenfrom = 2
-- 唯一字段名称
uniquestr = 'token'
if tokenfrom == 1 then
token,e = ngx.req.get_headers()[uniquestr]
else if tokenfrom == 2 then
ngx.req.read_body()
token,e = ngx.req.get_post_args()[uniquestr]
end
end
-- 这里用于处理不带token字段、或者token字段为空的时候不进行防护处理。
-- 比如接口和页面共存的时候 js\css\jpg等资源文件是不含token的。
if token == nil then
ngx.exec("@php")
else
if token == "" then
ngx.exec("@php")
end
end
redis = require("resty.redis")
red = redis:new()
red:set_timeout(1000)
ok,err = red:connect('127.0.0.1','6379')
if not ok then
ngx.say('redis connect failed',err)
end
-- redis 认证,如果空密码则注释掉
--ok,err = red:auth('123')
--if not ok then
-- ngx.say('auth failed:',err)
--end
-- redis 切换库
--ok, err = red:select(1)
--if not ok then
-- ngx.say("failed to select db: ", err)
--end
get,e = red:get(token)
if get ~= ngx.null then
get = tonumber(get)
if get >= countper then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
count = get + 1
e = red:ttl(token)
red:set(token, count)
red:expire(token, e)
if count == countper then
red:expire(token, blocktime)
end
else
red:set(token, 1)
red:expire(token, timeout)
end
ok, err = red:close()
ngx.exec("@php")
@php部分为nginx中location 内部调用
以上代码保存到/home/software/openresty/nginx/lua/default.lua中。
openresty中nginx部分配置
location / {
lua_code_cache on;
content_by_lua_file /home/software/openresty/nginx/lua/default.lua;
}
location @php
{
proxy_pass http://127.0.0.1:8888;
}
这段防CC代码比较适用于接口调用或者前后分离的站,因为一般都是通过接口访问,接口会带认证信息,这个认证信息可以做为判断唯一来源。
像普通网站没有比较适合判断唯一的地方,仅仅一个ip不能满足,而且ip可以通过代理更换,所以不适用于普通类型网站。
上面的配置参数表示:
以post请求中token字段做为redis中key唯一值,在60秒内请求次数超过10次后,则阻断120秒。待key超时后(120秒),则可以继续访问。