插件窝 干货文章 ubuntu Install nginx Lua and configure waf

ubuntu Install nginx Lua and configure waf

Nginx WAF Lua Rule 242    来源:    2025-05-10

Installing Nginx with Lua Support and Configuring WAF on Ubuntu

1. Install Prerequisites

First, update your package list and install the necessary dependencies:

sudo apt update
sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev wget unzip git

2. Install OpenResty (Nginx with Lua)

OpenResty is a full-fledged web platform that integrates Nginx with LuaJIT:

sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:openresty/ppa
sudo apt update
sudo apt install -y openresty

Alternatively, you can compile Nginx with Lua support manually.

3. Install Lua Modules

Install commonly needed Lua modules:

sudo apt install -y luarocks
sudo luarocks install lua-resty-http
sudo luarocks install lua-resty-cookie
sudo luarocks install lua-resty-string

4. Configure Nginx with Lua

Edit your Nginx configuration (typically at /usr/local/openresty/nginx/conf/nginx.conf or /etc/nginx/nginx.conf):

http {
    lua_package_path "/usr/local/lib/lua/?.lua;;";
    lua_package_cpath "/usr/local/lib/lua/?.so;;";

    init_by_lua_block {
        -- Initialize any global Lua variables here
    }

    server {
        listen 80;
        server_name yourdomain.com;

        location / {
            access_by_lua_block {
                -- WAF rules will go here
            }

            proxy_pass http://your_backend;
        }
    }
}

5. Implement Basic WAF Rules

Create a new Lua file for your WAF rules (e.g., /etc/nginx/waf.lua):

local waf = {}

-- Rule sets
waf.rules = {
    sql_injection = {
        patterns = {
            "['\"]%s*or%s*['\"]",
            "union%s+all",
            "select%s.*from",
            "insert%s.*into",
            "delete%s.*from",
            "update%s.*set",
            "drop%s+table",
            "truncate%s+table",
            "create%s+table",
            "exec%s*%(",
            "xp_cmdshell"
        },
        action = "deny"
    },
    xss = {
        patterns = {
            "<script>",
            "javascript:",
            "onload=",
            "onerror=",
            "onclick=",
            "eval%(",
            "alert%(",
            "document%.cookie"
        },
        action = "deny"
    },
    path_traversal = {
        patterns = {
            "%.%.%/",
            "%.%.%\\",
            "etc/passwd",
            "boot.ini"
        },
        action = "deny"
    }
}

-- Check if a string matches any pattern
function waf.match_pattern(str, patterns)
    for _, pattern in ipairs(patterns) do
        if ngx.re.find(str, pattern, "isjo") then
            return true
        end
    end
    return false
end

-- Main WAF function
function waf.run()
    local uri = ngx.var.request_uri
    local args = ngx.req.get_uri_args()
    local headers = ngx.req.get_headers()
    local request_body = ""

    -- Check request body for POST requests
    if ngx.req.get_method() == "POST" then
        ngx.req.read_body()
        request_body = ngx.req.get_body_data() or ""
    end

    -- Check each rule category
    for rule_name, rule in pairs(waf.rules) do
        -- Check URI
        if waf.match_pattern(uri, rule.patterns) then
            ngx.log(ngx.WARN, "WAF blocked URI: ", uri, " for rule: ", rule_name)
            if rule.action == "deny" then
                return ngx.exit(ngx.HTTP_FORBIDDEN)
            end
        end

        -- Check GET args
        for _, arg in pairs(args) do
            if type(arg) == "string" and waf.match_pattern(arg, rule.patterns) then
                ngx.log(ngx.WARN, "WAF blocked argument: ", arg, " for rule: ", rule_name)
                if rule.action == "deny" then
                    return ngx.exit(ngx.HTTP_FORBIDDEN)
                end
            end
        end

        -- Check request body
        if waf.match_pattern(request_body, rule.patterns) then
            ngx.log(ngx.WARN, "WAF blocked request body for rule: ", rule_name)
            if rule.action == "deny" then
                return ngx.exit(ngx.HTTP_FORBIDDEN)
            end
        end

        -- Check headers
        for _, h in pairs(headers) do
            if type(h) == "string" and waf.match_pattern(h, rule.patterns) then
                ngx.log(ngx.WARN, "WAF blocked header for rule: ", rule_name)
                if rule.action == "deny" then
                    return ngx.exit(ngx.HTTP_FORBIDDEN)
                end
            end
        end
    end
end

return waf

6. Update Nginx Configuration to Use WAF

Modify your Nginx configuration to include the WAF:

http {
    lua_package_path "/etc/nginx/?.lua;;";

    server {
        listen 80;
        server_name yourdomain.com;

        location / {
            access_by_lua_file /etc/nginx/waf.lua;

            proxy_pass http://your_backend;
        }
    }
}

7. Test and Reload Nginx

Test your configuration and reload Nginx:

sudo nginx -t
sudo systemctl restart nginx

8. Advanced Options (Optional)

For a more comprehensive WAF, consider:

  1. Install libinjection for better SQLi and XSS detection:

    git clone https://github.com/libinjection/libinjection.git
    cd libinjection
    make
    sudo make install
    
  2. Use existing WAF solutions like:

  3. Enable logging for blocked requests.

  4. Implement rate limiting to prevent brute force attacks.

9. Monitoring and Maintenance

Regularly update your WAF rules and monitor logs:

# Check WAF blocks in Nginx error log
sudo tail -f /var/log/nginx/error.log | grep "WAF blocked"

This setup provides a basic but effective WAF using Nginx and Lua. For production environments, consider more sophisticated solutions or commercial WAF products that offer better protection and easier rule management.