插件窝 干货文章 如何在Nginx中使用Lua防护Web安全漏洞

如何在Nginx中使用Lua防护Web安全漏洞

ngx local end then 528    来源:    2025-04-20

使用Nginx + Lua防护Web安全漏洞指南

Nginx结合Lua脚本(Lua-nginx-module)可以构建强大的Web应用防火墙(WAF),有效防护常见Web安全漏洞。以下是实现方案:

一、基础环境配置

  1. 安装OpenResty(推荐)

    # Ubuntu/Debian
    sudo apt-get install -y software-properties-common
    sudo add-apt-repository -y ppa:openresty/ppa
    sudo apt-get update
    sudo apt-get install -y openresty
    
    # CentOS/RHEL
    sudo yum install yum-utils
    sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
    sudo yum install -y openresty
    
  2. 验证安装

    nginx -v
    # 应显示OpenResty版本
    

二、常见漏洞防护实现

1. SQL注入防护

location / {
    access_by_lua_block {
        local args = ngx.req.get_uri_args()
        for key, val in pairs(args) do
            if type(val) == "string" then
                if ngx.re.match(val, [[(?:')|(?:--)|(\b(select|update|delete|insert|drop|alter|truncate)\b)]], "i") then
                    ngx.log(ngx.ERR, "SQL injection detected: ", val)
                    return ngx.exit(403)
                end
            end
        end
    }
    # 其他配置...
}

2. XSS防护

location / {
    access_by_lua_block {
        local args = ngx.req.get_uri_args()
        for key, val in pairs(args) do
            if type(val) == "string" then
                if ngx.re.match(val, [[<script|<iframe|javascript:|onload\s*=|onerror\s*=]], "i") then
                    ngx.log(ngx.ERR, "XSS attack detected: ", val)
                    return ngx.exit(403)
                end
            end
        end
    }
}

3. 文件路径遍历防护

location / {
    access_by_lua_block {
        local uri = ngx.var.uri
        if ngx.re.match(uri, [[\.\./|\.\.\\]]) then
            ngx.log(ngx.ERR, "Path traversal attack detected: ", uri)
            return ngx.exit(403)
        end
    }
}

4. CSRF防护

location /protected/ {
    access_by_lua_block {
        local headers = ngx.req.get_headers()
        local referer = headers["Referer"]

        if not referer or not ngx.re.match(referer, "^https?://(www\\.)?yourdomain\\.com") then
            ngx.log(ngx.ERR, "CSRF attempt detected")
            return ngx.exit(403)
        end
    }
}

5. 速率限制(防暴力破解)

lua_shared_dict my_limit_req_store 100m;

location /login {
    access_by_lua_block {
        local limit_req = require "resty.limit.req"
        local lim, err = limit_req.new("my_limit_req_store", 5, 10) -- 5 req/sec, burst 10

        if not lim then
            ngx.log(ngx.ERR, "failed to instantiate limit.req: ", err)
            return ngx.exit(500)
        end

        local key = ngx.var.binary_remote_addr
        local delay, err = lim:incoming(key, true)

        if not delay then
            if err == "rejected" then
                return ngx.exit(429)
            end
            ngx.log(ngx.ERR, "failed to limit req: ", err)
            return ngx.exit(500)
        end

        if delay >= 0.001 then
            ngx.sleep(delay)
        end
    }

    # 其他配置...
}

三、高级防护功能

1. 自定义WAF规则

创建/etc/nginx/waf.lua:

local _M = {}

_M.rules = {
    {rule = [[union\s+select]], msg = "SQL injection"},
    {rule = [[<script]], msg = "XSS attack"},
    {rule = [[\.\./]], msg = "Path traversal"},
    -- 添加更多规则...
}

function _M.filter()
    local args = ngx.req.get_uri_args()
    local headers = ngx.req.get_headers()
    local uri = ngx.var.uri

    -- 检查URI
    for _, rule in ipairs(_M.rules) do
        if ngx.re.match(uri, rule.rule, "i") then
            ngx.log(ngx.ERR, "WAF blocked URI: ", rule.msg)
            return true
        end
    end

    -- 检查GET参数
    for key, val in pairs(args) do
        if type(val) == "string" then
            for _, rule in ipairs(_M.rules) do
                if ngx.re.match(val, rule.rule, "i") then
                    ngx.log(ngx.ERR, "WAF blocked args: ", rule.msg, " key=", key)
                    return true
                end
            end
        end
    end

    -- 检查POST数据
    ngx.req.read_body()
    local post_args = ngx.req.get_post_args()
    if post_args then
        for key, val in pairs(post_args) do
            if type(val) == "string" then
                for _, rule in ipairs(_M.rules) do
                    if ngx.re.match(val, rule.rule, "i") then
                        ngx.log(ngx.ERR, "WAF blocked POST: ", rule.msg, " key=", key)
                        return true
                    end
                end
            end
        end
    end

    return false
end

return _M

在Nginx配置中使用:

location / {
    access_by_lua_block {
        local waf = require "waf"
        if waf.filter() then
            ngx.exit(403)
        end
    }
}

2. IP黑白名单

lua_shared_dict ip_blacklist 10m;
lua_shared_dict ip_whitelist 10m;

location / {
    access_by_lua_block {
        local blacklist = ngx.shared.ip_blacklist
        local whitelist = ngx.shared.ip_whitelist

        local client_ip = ngx.var.remote_addr

        -- 检查白名单
        if whitelist:get(client_ip) then
            return
        end

        -- 检查黑名单
        if blacklist:get(client_ip) then
            ngx.log(ngx.ERR, "Blocked IP: ", client_ip)
            return ngx.exit(403)
        end

        -- 动态添加IP到黑名单的示例(如登录失败多次)
        -- local failures = blacklist:get(client_ip.."_failures") or 0
        -- if failures > 5 then
        --     blacklist:set(client_ip, true, 3600) -- 封禁1小时
        -- end
    }
}

四、性能优化建议

  1. 使用缓存:将频繁使用的规则或IP列表缓存在共享内存中
  2. 正则优化:使用简单的正则表达式,避免复杂匹配
  3. 选择性检查:只对敏感路径进行严格检查
  4. 日志分级:错误日志和访问日志分开记录

五、完整配置示例

http {
    lua_package_path "/etc/nginx/lua/?.lua;;";
    lua_shared_dict my_limit_req_store 100m;
    lua_shared_dict ip_blacklist 10m;

    init_by_lua_block {
        require "resty.core"
    }

    server {
        listen 80;

        location / {
            access_by_lua_block {
                local waf = require "waf"
                if waf.filter() then
                    ngx.exit(403)
                end

                -- IP黑名单检查
                local blacklist = ngx.shared.ip_blacklist
                if blacklist:get(ngx.var.remote_addr) then
                    return ngx.exit(403)
                end
            }

            proxy_pass http://backend;
        }

        location /login {
            access_by_lua_block {
                -- 速率限制
                local limit_req = require "resty.limit.req"
                local lim = limit_req.new("my_limit_req_store", 5, 10)
                local delay, err = lim:incoming(ngx.var.binary_remote_addr, true)
                if not delay and err == "rejected" then
                    return ngx.exit(429)
                end

                -- 额外安全检查
                local args = ngx.req.get_uri_args()
                for key, val in pairs(args) do
                    if type(val) == "string" and ngx.re.match(val, [[union\s+select]], "i") then
                        ngx.log(ngx.ERR, "Login SQLi attempt")
                        return ngx.exit(403)
                    end
                end
            }

            proxy_pass http://backend;
        }
    }
}

六、注意事项

  1. 规则需要定期更新以应对新型攻击
  2. 生产环境应先测试规则,避免误拦截合法请求
  3. 结合日志分析工具(如ELK)监控拦截情况
  4. 对于复杂应用,建议使用专业WAF(如ModSecurity)作为补充

通过以上配置,您可以构建一个基本的Web应用防护层,有效拦截常见Web攻击。根据实际业务需求调整规则和防护策略。