Funny ngy_lua outcome

Nginx User nginx at nginxuser.net
Sun Oct 23 14:20:07 UTC 2011


SETUP
***CONF FILE***
server {
	location @proxy {
		access_by_lua_file '/etc/nginx/firewall.lua';
		proxy_cache proxy.capture360.net;
		proxy_pass http://127.0.0.1:8080;
		include /etc/nginx/proxy.default;
	}
	location /error_docs {
		internal;
		alias /usr/share/nginx/html;
		
		sub_filter '<!-- SubTag -->' '$host';
		sub_filter_once off;
	}
	location @pretty_urls {
		# -- Several rewrite X Y break lines
		
		rewrite_by_lua 'ngx.exec("@proxy");';
	}
	location / {
		try_files $uri $uri/ @pretty_urls;
	}
	location ~ .+\.php$ {
		location ~ \..*/.*\.php$ { return 400; }
		rewrite_by_lua 'ngx.exec("@proxy");';
	}	
}


***FIREWALL.LUA***
-- F. Check "GET" Args
	if ngx.var.request_method == "GET" then
		local args = ngx.req.get_uri_args()
		for key, val in pairs(args) do
			if type(val) == "table" then
				my_arg = table.concat(val, " ")
			else
				my_arg =  val
			end
			if my_arg and my_arg ~= "" and type(my_arg) ~= "boolean" then
				rule_id = regex_rules.check()
				if rule_id then
					ngx.log(ngx.INFO, "Firewall Match: Rule " .. rule_id .. " on
POST: " .. my_arg)
					ngx.exit(ngx.HTTP_BAD_REQUEST)
				end
			end
		end
	end
	
-- G. Check "POST" Args
	if ngx.var.request_method == "POST" then
		ngx.req.read_body()
		local args = ngx.req.get_post_args()
		for key, val in pairs(args) do
			if type(val) == "table" then
				my_arg = table.concat(val, " ")
			else
				my_arg = val
			end
			if my_arg and my_arg ~= "" and type(my_arg) ~= "boolean" then
				rule_id = regex_rules.check()
				if rule_id then
					ngx.log(ngx.INFO, "Firewall Match: Rule " .. rule_id .. " on
POST: " .. my_arg)
					ngx.exit(ngx.HTTP_BAD_REQUEST)
				end
			end
		end
		ngx.req.discard_body()
	end

***REGEX_RULES.LUA***
module("regex_rules", package.seeall)
function check()
-- <id>00</id>
			local query_string = "//"
			local query_match = ngx.re.match(my_arg, query_string, "io")
			-- generic attacks
			-- <impact>9</impact>
			if query_match then
				return "00"
			end
-- <id>01</id>
			local query_string = "(?:\"[^\"]*[^-]?>)|(?:[^\\\w\\\s]\\\s*\\\/>)|(?:>\")"
			local query_match = ngx.re.match(my_arg, query_string, "io")
			-- finds html breaking injections including whitespace attacks -- xss -- csrf
			-- <impact>4</impact>
			if query_match then
				return "01"
			end
.....


ISSUES
1. A googlebot visit while testing a post string designed to be
blocked "language=vbscript" is also blocked as the googlebot request
is also tested against the same string.

2. Despite the "return id" line, the regex rules are run to the end.
I.E., if there is a match on Rule 02, the rest are still run anyway
and only after the last is evaluated is the 400 error returned.

3. The log from "ngx.log" does not seem to be produced.


COMMENTARY
Abridged debug log with commentary here: http://pastebin.com/A0cXpHwg
(Lost the one with thegooglebot issue)

Issue 1 seems to be a variable scope issue with "my_arg" but when I
use"local" regex_rules.check() gets fed a blank.

Could the log thing be a level issue? I.E. "ngx.INFO" is too low??

Thanks



More information about the nginx mailing list