運維同學,線上機器怎麼又雙叒叕掛了?
對爬蟲也是相愛相殺多年,我對線上爬蟲的應對出現的幾個階段:
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 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 main()
如果這個方式不行,後面會繼續更新,大概方法分享給深受爬蟲摧殘的運維小夥伴們。