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秒),则可以继续访问。
原创文章,转载请注明。本文链接地址: https://www.rootop.org/pages/4447.html