Nginx结合Lua脚本(Lua-nginx-module)可以构建强大的Web应用防火墙(WAF),有效防护常见Web安全漏洞。以下是实现方案:
安装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
验证安装
nginx -v
# 应显示OpenResty版本
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
}
# 其他配置...
}
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
}
}
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
}
}
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
}
}
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
}
# 其他配置...
}
创建/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
}
}
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
}
}
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;
}
}
}
通过以上配置,您可以构建一个基本的Web应用防护层,有效拦截常见Web攻击。根据实际业务需求调整规则和防护策略。