<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    WAF開發之灰度轉發

    VSole2021-07-02 17:01:02

    簡介

    突然心血來潮想寫一下基于lua實現灰度轉發的文章。

    根據前文內容的openresty處理階段這一環節,假如要實現灰度流量的轉發,需要在balancer這個階段進行處理。這個階段類似于nginx的upstream作用域

    upstream backend {  server test.com  test;}
    

    原生的upstream其實是可以實現灰度流量轉發的,但是主要策略是基于權重比例來流量的轉發,無法實現顆粒度細的流量轉發,為此,我使用lua代碼實現了四種灰度流量轉發策略:

    基于權重比例轉發;
    基于IP地址轉發;
    基于地區位置轉發;
    基于HTTP字段轉發(通用);

    首先需要了解在這個階段可以支持的操作有什么內容:

    #告訴openresty流量要轉到什么后端服務器syntax:ok, err = balancer.set_current_peer(host, port)
    #設置嘗試錯誤次數syntax:ok, err = balancer.set_more_tries(count)
    #獲取上次失敗的原因,我用來剔除失效的后端服務器syntax:state_name, status_code = balancer.get_last_failure()
    #設置超時時間syntax:ok, err = balancer.set_timeouts(connect_timeout, send_timeout, read_timeout
    

    接著根據上面的內容編寫一個轉發流量到后端的函數

    --ip_lists是一個后端服務器列表,比如(192.168.1.2,192.168.1.3,192.168.1.4),port是固定的,local function forward_server(ip_lists, port)--設置錯誤嘗試失敗次數    if not ngx.ctx.tries then        ngx.ctx.tries = 0    end#判斷后端服務器列表有多少個,確定重試次數    if ngx.ctx.tries < #ip_lists then        local set_more_tries_ok, set_more_tries_err = balancer.set_more_tries(1)        if not set_more_tries_ok then            ngx.log(ngx.ERR, "failed to set the current peer: ", set_more_tries_err)        elseif set_more_tries_err then            ngx.log(ngx.ALERT, "set more tries: ", set_more_tries_err)        end    end
        ngx.ctx.tries = ngx.ctx.tries + 1#確定有效的后端服務器列表    if not ngx.ctx.ip_lists then        ngx.ctx.ip_lists = ip_lists    end#確定客戶端IP指向一個后端服務器,用于保持會話    local first_count = {}    table.insert(first_count, string.sub(ngx.var.remote_addr, 1, 1))    table.insert(first_count, string.sub(ngx.var.remote_addr, -1))    local ip_count = (tonumber(table.concat(first_count)) % #ngx.ctx.ip_lists) + 1
        local _host = ngx.ctx.ip_lists[ip_count]    local state_name, state_code = balancer.get_last_failure()#剔除失效后端服務器    if state_name == "failed" then        for k, v in ipairs(ngx.ctx.ip_lists) do            if v == _host then                if not (#ngx.ctx.ip_lists == 1) then                    table.remove(ngx.ctx.ip_lists, k)                    ip_count = (string.sub(ngx.var.remote_addr, -1) % #ngx.ctx.ip_lists) + 1                    _host = ngx.ctx.ip_lists[ip_count]                end            end        end    end#一切沒有問題之后,直接流量轉發    local ok, err = balancer.set_current_peer(_host, port)
        if not ok then        ngx.log(ngx.ERR, "failed to set the current peer: ", err)    end
    end
    

    最后聊聊四個灰度轉發策略的編寫

    基于權重比例轉發策略

    基于權重比例比較簡單,就是使用隨機數落到那一個后端服務器里面。

    比如{“192.168.1.20”:“20”,“192.168.1.30”:30}

    local weight_list = {}local iplist = {}iplist['192.168.1.20']=20iplist['192.168.1.30']=30
    for key,value in pairs(iplist) do    for i=1, value do        table.insert(weight_list,key)     endend
    local random_value = math.random(1, #weight_list)print(random_value)print(weight_list[random_value])
    

    基于IP比例轉發策略

    local iputils = require "resty.waf.iputils"
    

    基于iputils 庫,用于處理客戶端IP的地址轉發(支持IP地址和網段)

    local ip_forward_list={"192.168.1.2","192.168.20.0/24"}local ip_list = iputils.parse_cidrs(ip_forward_list)
    if iputils.ip_in_cidrs(remote_ip, ip_list) then   --如果IP段灰度策略符合,轉發到灰度服務器    return  forward_server(gray_server, gray_port)end
    

    基于地區灰度轉發策略

    local geo = require 'resty.waf.maxminddb'
    if not geo.initted() then    geo.init("/opt/GeoLite2-City.mmdb") --需要在該目錄設置geo庫end
    local res, err = geo.lookup(remote_ip)
    if res then    if res['city'] then        local city_name = res['city']['names']['zh-CN']        --查看當前IP所屬的城市        --ngx.log(ngx.ERR,city_name)        for _, _value in pairs(region_forward_data) do
                local gray_server = _value['gray_server']            local gray_port = _value['gray_port']
                local region = _value['content'][1]['content']            if region == city_name then                return forward_server(gray_server, gray_port) --如果地區灰度策略符合,轉發到灰度服務器            end        end    endend
    

    基于通用配置轉發策略

    我是用jxwaf里面的處理HTTP字段代碼,就不造輪子,具體開發思路可以參考jxwaf的自定義規則功能

    local waf = require "resty.waf.waf"local request = require "resty.waf.request"local operator = require "resty.waf.operator"local transform = require "resty.waf.transform"
    

    PS:有人對CC防御的模塊開發有興趣嗎?

    waf
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    0x00 簡介WAFNinja 簡介WAFNinja 是一款采用Python編寫的命令行工具。它通過自動化步驟來幫助滲透測試者來繞過WAF,而這些步驟對于繞過輸入驗證來說是必需的。
    WAF指紋識別工具
    2022-04-11 06:18:47
    原理發送正常的 HTTP 請求并分析響應;這確定了許多 WAF 解決方案。如果不成功,則發送多個HTTP 請求,并使用簡單的邏輯來示例就是WAF
    WAF繞過工具
    2022-03-02 06:34:03
    Nemesida WAF 團隊 ( nemesida-waf.com ) 的 WAF Bypass 是一個開源工具 (Python3),用于使用預定義的有效負載檢查任何 WAF 的誤報/誤報數量(如果需要,可以更改有效負載集)。使用前關閉禁用模式。 為內部需求開發的腳本,包括用于測試 Nemesis WAF 和 Nemesida WAF Free,但您可以使用它來測試任何 WAF
    如果流量都沒有經過WAFWAF當然無法攔截攻擊請求。當前多數云WAF架構,例如百度云加速、阿里云盾等,通過更改DNS解析,把流量引入WAF集群,流量經過檢測后轉發請求到源站。如圖,dict.com接入接入WAF后,dict.com的DNS解析結果指向WAF集群,用戶的請求將發送給WAF集群,WAF集群經過檢測認為非攻擊請求再轉發給源站。
    WAF分為非嵌入型WAF和嵌入型WAF,非嵌入型指的是硬WAF、云WAF、虛擬機WAF之類的;嵌入型指的是web容器模塊類型WAF、代碼層WAF
    Bypass安全狗MySQL注入
    一般的做法,是解綁域名,再到web服務上綁定該域名。也就是說,規則引擎分為兩塊,對請求過濾和對響應過濾,而對請求過濾分為兩大步,網絡層過濾和應用層過濾。
    WAF分類及繞過思路
    2021-11-26 05:17:12
    WAF分為非嵌入型WAF和嵌入型WAF,非嵌入型指的是硬WAF、云WAF、虛擬機WAF之類的;嵌入型指的是web容器模塊類型WAF、代碼層WAF
    WAF CDN 的識別方法
    2021-11-22 07:37:57
    CDN 是構建在現有網絡基礎之上的智能虛擬網絡,依靠部署在各地的邊緣服務器,通過中心平臺的負載均衡、內容分發、調度等功能模塊,使用戶就近獲取所需內容,降低網絡擁塞,提高用戶訪問響應速度和命中率。CDN 的關鍵技術主要有內容存儲和分發技術。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类