当我遇到了爬虫

运维同学,线上机器怎么又双叒叕挂了?

 思路:

 

对爬虫也是相爱相杀多年,我对线上爬虫的应对出现的几个阶段:

1、分析日志,找出异常请求,封ip。

2、通过waf,针对某个uri ,进行限流(并且人机识别),控制的还是源ip,起初有点成效。

3、遇到大量单ip,触发不到人机识别,通过nginx自带的limit_req_zone进行uri限制,发现有效果,但是会误杀很多无辜。

map $request_uri $xx_limit {
    "~*/xxx/" "/xxx/";
    default "";
}
limit_req_zone $xx_limit zone=api_limit:10m rate=5r/s;

当请求路径包含/xxx/时,设置$xx_limit 为/xxx/,默认值为空,为空则limit_req_zone 不生效




limit_req zone=api_limit burst=10 delay=5;

每秒标准5个请求,burst可以让突发请求到10个,delay是当有突发请求时前五个直接请求,剩余的rate=5/s=200ms/个,消费1个,等待200ms

 

4、通过openresty,将请求相关数据发送到请求数据分析接口,分析之后返回结果,再由openresty判断是否放行,到目前为止立竿见影。

 

数据分析接口大概得思路就是:此时做一些限制已经没有用了(后端代码也无法更改),去推理人的行为,一个正常人要访问网站时会怎么操作,爬虫毕竟只是爬虫,没法跟人一样。

local http = require "resty.http"
local httpc = http.new()
local json = require("cjson")

local uri = ngx.var.noparams_uri
local headers=ngx.req.get_headers()
local ip=headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr
local ua=headers["User-Agent"] or ''
local white_ua={"xxxx",} -- ua 白名单


local api_server="xxx:1234"
local topic_id = "xxxxx"

function req_fast_api()
    --return false 是异常请求,true是正常请求

    local data = {
        TopicId = "xxxxxxx",
        From = 1710086694000,
        To = 1717151565000,
        Query = '"remote_addr:\"' .. ip .. '\""',
        Limit = 100
    }

    local jsonStr = json.encode(data)

    local resp, err = httpc:request_uri("http://" .. api_server .. "/xxx/xxx/xxxx", {
        method = "POST",
        body = jsonStr,
        headers = {
            ["Content-Type"] = "application/json",
        },
    })

    if not resp then
        ngx.log(ngx.ERR, "cls 日志接口挂了。")
        return 500, "true"
    end

    return resp.status, resp.body
end


function main()
    -- 校验ua是否在白名单中
    local outer_i
    for i, v in ipairs(white_ua) do
        if string.find(ua, v) then
            break
        else
            outer_i = i
        end
    end

    if outer_i == #white_ua then
        -- ua不在白名单中
        ngx.header["Server"] = "xxxxx/xxx"
        local status, body = req_fast_api()
        ngx.log(ngx.ERR, ip .. "日志接口返回:" .. body .. ",且ua不在白名单中。")
        if body == "false" then
            ngx.status = ngx.HTTP_BAD_REQUEST
            ngx.say("xxxx")
            ngx.exit(ngx.HTTP_BAD_REQUEST)
        end
    end
end

local m = ngx.re.match(uri, "^/xxxxx/.*$", "jo")

if m then
    main()
else
    ngx.log(ngx.ERR, "非xxxx的忽略" .. uri)
end

 

posted @ 2024-06-03 11:43  JvvYou  阅读(6)  评论(0编辑  收藏  举报