WAF 規則

Plus 提供的 WAF 功能也是基於 Edgelang 實現的,所以使用者可以透過 Edgelang 編寫高效的 WAF 規則集。

我們的 WAF 模組與其他 WAF 模組在使用相同規則集的情況下的效能對比圖。

這裡我們提供一個攔截 /root.exe 惡意請求的例子。

建立 WAF 模組

WAF 模組 與普通 Edgelang 模組的區別就是 WAF 模組需要使用 waf-mark-risk 標記惡意請求。我們建立一個名為 reject-root 的 WAF 模組,原始碼如下:

uri eq "/root.exe" =>
    waf-mark-risk(msg: "reject root.exe");

一個 WAF 模組中也可以包含多條規則,例如:

uri eq "/root.exe" =>
    waf-mark-risk(msg: "reject root.exe");

uri contains "/other.exe" =>
    waf-mark-risk(msg: "reject other.exe");

匯出 WAF 模組

點選儲存並編譯,然後可以從下面的編譯歷史中下載編譯後的 zip 壓縮包。

解壓後將其中的 .ljbc 檔案複製到 nginx.conf 中指定的 lua_package_path 目錄下。

此外,在列表頁面可以透過多選 WAF 模組的方式一次性匯出多個 WAF 模組。

使用 WAF 模組

需要使用 orwaf:add_rule_set 新增規則集,然後在服務入口前使用 orwaf:run 執行指定的規則集。 如果請求命中了 WAF 規則集,orwaf:run 會返回命中資訊。

  • orwaf:add_rule_set(rule_set_name, rule_set_module_name)

    • rule_set_name: 給規則集定義一個名稱,在後面將透過名稱來選擇要執行的規則集,可以和 WAF 模組名不同。
    • rule_set_module_name: WAF 模組名。
  • orwaf:run(rule_set_names)

    • rule_set_names: 需要執行的規則集列表

以下是一個完整的 nginx.conf 示例。

worker_processes  auto;

events {
    worker_connections  1024;
}

http {
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    lua_shared_dict dymetric_version 1m;
    lua_shared_dymetrics dymetrics 10m;

    init_worker_by_lua_block {
        local orwaf = require "orwaf".new()
        local res, err = orwaf:add_rule_set("reject-root")
        if not res then
            ngx.say("err: ", err)
            return
        end
    }

    server {
        listen       127.0.0.1:80;
        listen       [::1]:80;
        server_name  localhost;

        location / {
            content_by_lua_block {
                local matches, err = orwaf:run({"reject-root"})
                if matches then
                    ngx.log(ngx.ERR, "ok: matches = ", require("cjson.safe").encode(matches))
                    ngx.exit(403)
                end
            }
        }
    }
}

內建規則集

除了可以透過 WAF 模組定義的規則集,我們也內建了 OWASP 的規則集。

  • scanner_detection
  • protocol_enforcement
  • protocol_attack
  • attack_lfi
  • attack_rfi
  • attack_rce
  • attack_php
  • attack_nodejs
  • attack_xss
  • attack_sqli
  • attack_session_fixation
  • attack_java

呼叫方法和自定義規則集一樣。

location / {
    content_by_lua_block {
        local matches, err = orwaf:run({"scanner_detection", "protocol_enforcement", "protocol_attack"})
        if matches then
            ngx.log(ngx.ERR, "ok: matches = ", require("cjson.safe").encode(matches))
            ngx.exit(403)
        end
    }
}