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
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.
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
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;
}
}
}
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
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;
}
}
}
Test your configuration and reload Nginx:
sudo nginx -t
sudo systemctl restart nginx
For a more comprehensive WAF, consider:
Install libinjection for better SQLi and XSS detection:
git clone https://github.com/libinjection/libinjection.git
cd libinjection
make
sudo make install
Use existing WAF solutions like:
Enable logging for blocked requests.
Implement rate limiting to prevent brute force attacks.
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.