ModSecurity – SecRule Based on Original Browser URL

apache-2.4mod-rewritemod-securityWordpress

I'm working on a Symfony 2 site, and am trying to create a ModSecurity rule to match a particular browser URL. IE example.com/results

Symfony 2 internally rewrites all requests to app.php using rules in .htaccess, so when I check REQUEST_URI in the ModSecurity rule, it is set to app.php. I have tried any other server parameter that appears relevant, but all are either app.php or blank.

Is there any way to create a ModSecurity rule in a config file that is based on the URL requested by the browser, rather than on the result of an internal rewrite?

The same issue appears to exist with CMS's like wordpress: everything is rewritten to index.php, so I can't find any way to apply modsec rules to a specific route. (I figured since WP is so common I might be able to find an answer by searching for the same problem there.)

Best Answer

It looks like I can use the server variable THE_REQUEST, as per this answer: https://stackoverflow.com/a/27968463/160565

:

I'm using mod_rewrite to dump THE_REQUEST into an environment variable just above the mod_security rules, then matching on that.

As noted, THE_REQUEST is an Apache server variable used by mod_rewrite, not a mod_security variable. The directly equivalent variable in mod_security is REQUEST_LINE, ie. the first line of the request. This takes the form of a string like:

GET /foo/bar HTTP/1.1

THE_REQUEST (mod_rewrite) variable does not change when the URL is rewritten, whereas REQUEST_URI (mod_rewrite) does.

However, I'm a bit surprised that the REQUEST_URI (mod_security) variable is returning the rewritten URL (maybe this is to do with the ordering of directives or using mod_security embedded?), instead of the originally requested URL, unless you are actually using the REQUEST_URI (mod_rewrite) variable (assigning this to an env var?) in your mod_security rule?

just above the mod_security rules...

The mod_security rules should probably be at the top of your file, if not already, before any mod_rewrite directives. (Although whether the order really matters I'm not sure.)

Note that the REQUEST_URI (mod_security) variable is not the same as the REQUEST_URI (mod_rewrite) variable, despite being named the same. Notably, REQUEST_URI (mod_security) contains the query string, whereas REQUEST_URI (mod_rewrite) does not.

Reference:


UPDATE:

... the REQUEST_URI (mod_security) variable is returning the rewritten URL

You may be running the mod_security rule too late in the request, ie. in the wrong phase? To process the requested URL you should be comparing against REQUEST_URI in either phase 1 or 2 (the request). Later phases (ie. 3 - 5) will process against the response which may explain why you are seeing the rewritten URL and not the requested URL.

The phase is set in the action argument or SetDefaultAction directive. For example:

SecDefaultAction "log,pass,phase:2,id:4"
SecRule REQUEST_URI "attack" "phase:1,id:52,t:none,t:urlDecode,t:lowercase,t:normalizePath"

The five phases are:

  1. Request headers (REQUEST_HEADERS)
  2. Request body (REQUEST_BODY)
  3. Response headers (RESPONSE_HEADERS)
  4. Response body (RESPONSE_BODY)
  5. Logging (LOGGING)

Starting in ModSecurity version v2.7 there are aliases for some phase numbers:

2 - request
4 - response
5 - logging

Example:

SecRule REQUEST_HEADERS:User-Agent "Test" "phase:request,log,deny,id:127"

Reference: