这篇文章上次修改于 2955 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

注:原创,转载请注明来处

    最近公司短信验证码获取接口被攻击,查看nginx日志,访问的ip都是同一个,做了一个简单的防刷脚本。

package.path = '/usr/local/luajit/share/lua/5.1/?.lua;'
package.cpath = '/usr/local/luajit/lib/lua/5.1/?.so;'
local function close_memcache(memc)  
    if not memc then  
        return  
    end  
    --释放连接(连接池实现)  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --连接池大小  
    local ok, err = memc:set_keepalive(pool_max_idle_time, pool_size)   
    if not ok then  
        ngx.log(ngx_ERR, "set memcache keepalive error : ", err)
    end  
end
local memcached = require "resty.memcached"
local cjson = require "cjson"
local uri = ngx.var.uri -- 获取当前请求的uri
local memc, err = memcached:new()
if not memc then 
    return
end
memc:set_timeout(1000)
local ok, err = memc:connect("10.117.*.*", 12211)
if not ok then
    return close_memcache(memc)
end
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
   clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
   clientIP = ngx.var.remote_addr
end
--短信验证码限制 一个小时内同一个ip访问超过3000次 此ip屏蔽10分钟
local smsstr = string.lower(uri)
local smsindex = string.find(smsstr, 'util/sms', 0)
if smsindex ~= nil then 
    local smsincrKey = "smsincr:"..clientIP..":"..ngx.md5(smsstr)..":"..os.date('%Y%m%d%H')
    local smslockKey = "smslock:"..clientIP..":"..ngx.md5(smsstr)
    local smslock = memc:get(smslockKey)
    smslock = tonumber(smslock)
    if smslock == 1 then   
       close_memcache(memc)
       ngx.print('{"error":"0","errorMsg":"","total":0,"data":[]}')
       ngx.exit(200)
    end
    local smsres, err = memc:incr(smsincrKey, 1)
    if smsres == nil then 
      smsres , err = memc:set(smsincrKey, 1, 3600)
    end
    smsres = tonumber(smsres)
    if smsres > 3000 then
         memc:set( smslockKey, 1, 1200 )
         memc:set( smsincrKey, 1 )
    end
end
--如果1秒种之内同一个ip访问的同一个地址的次数大于10次 此ip访问此地址时锁定10分钟不给访问
local incrKey = "lock:"..clientIP..":"..ngx.md5(uri)..":"..ngx.time()
local lockKey = "lock:"..clientIP..":"..ngx.md5(uri)
local lock = memc:get(lockKey)
lock = tonumber(lock)
if lock == 1 then   
   close_memcache(memc)
   ngx.exit(ngx.HTTP_FORBIDDEN)
end
local res, err = memc:incr(incrKey, 1)
if res == nil then 
  res , err = memc:set(incrKey, 1, 1)
end
res = tonumber(res)
if res > 10 then
     memc:set( lockKey, 1, 600 )
end
close_memcache(memc)