openresty自动拦截高频IP

有次公司的一些接口被人爬数据,导致web端异常缓慢。以前就知道openresty有这个功能,认识人往往就是这样,问题发生了,才去被动解决,反思!
调研解决方案如下
1.把nginx换成openresty
2.openresy + redis 去统计访问者访问次数,设置阈值,高于阈值直接返回403,一段时间后放开
调研结果如下
nginx location段配置


location  /redis_forbid {
        default_type 'text/html';
        access_by_lua_file lua/intercept.lua;
        content_by_lua_block {
        ngx.say("access")
        }
    }

intercept.lua

local redis = require("resty.redis")
local conn = redis:new()
conn:set_timeout(10000)

local redis_ip = "192.168.138.129"
local redis_port = 6379

local ok , err = conn:connect(redis_ip,redis_port)
if not ok then
    ngx.say("connect to redis fatal error: " ,err)
    return redis_close(conn)
end

-- ngx.exit(ngx.ERR) 客户端无法返回

local ttl = 60 -- key过期时间
local top_times = 10
local forbit_ttl = 100 --60内无法再次访问
local ip = ngx.var.remote_addr
local ip_total_times = conn:get(ip)

print("debug...................................." , conn:ttl(ip))


if ip_total_times ~= ngx.null then
    if (ip_total_times == "-1") then
        return ngx.exit(403)
    else
        this_ttl = conn:ttl(ip)
        
        if (this_ttl == -1) then --没有设置超时时间
            conn:set(ip,0)
            conn:expire(ip,ttl)
            return ngx.exit(ngx.OK)
        end
        v_times = tonumber(conn:get(ip)) + 1
        
        if (v_times > top_times) then
            
            conn:set(ip,-1)
            conn:expire(ip,forbit_ttl)
            return ngx.exit(ngx.OK)
        else
            print("debug 03")
            conn:set(ip,v_times)
            
            conn:expire(ip,this_ttl) -- 不要重新计时 
            return ngx.exit(ngx.OK)

        end     

        
    end
else
    print("key is not exists")
    conn:set(ip,1)
    conn:expire(ip,ttl)
    return ngx.exit(ngx.OK) --step done,如access_by_lua_file模块此处后,进入到content_by_lua_file模块处理
end

再写段测试程序

package main

import (
    "net/http"
    "fmt"
    "io/ioutil"
    "os"
)

func main()  {

    for i := 1 ; i<= 20 ;i++  {
        resp,err := http.Get("http://192.168.138.128/redis_forbid")
        defer resp.Body.Close()
        if err != nil {
            os.Exit(-1)
        }
        //time.Sleep(1*time.Second)
        body, _ := ioutil.ReadAll(resp.Body)
        fmt.Println("i is", i)
        fmt.Println(string(body))
    }

}

结果访问如下:

i is 12

403 Forbidden

403 Forbidden


openresty/1.13.6.2

你可能感兴趣的:(openresty自动拦截高频IP)