1

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.)

Nathan Stretch
  • 171
  • 1
  • 15

2 Answers2

1

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

Nathan Stretch
  • 171
  • 1
  • 15
  • 1
    `THE_REQUEST` is a mod_rewrite variable, not mod_security? The equivalent mod_security variable is `REQUEST_LINE`. – MrWhite Sep 13 '18 at 07:58
  • @MrWhite yes, I'm using mod_rewrite to dump THE_REQUEST into an environment variable just above the mod_security rules, then matching on that. I'll look into REQUEST_LINE though, as it would be simpler to have a variable to match directly. – Nathan Stretch Sep 13 '18 at 18:31
1

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:

MrWhite
  • 11,643
  • 4
  • 25
  • 40
  • The modsec rules are at the top of our virtualhost include file. However, the rewrite rules are in .htaccess. And yeah, we were trying to use the mod_security REQUEST_URI, which was giving us the post-rewrite path (/app.php) rather than the requested path. REQUEST_LINE does the job though! – Nathan Stretch Sep 14 '18 at 18:56
  • Interesting. In that case, I would have _expected_ the mod_security directives to be processed _before_ the URL was rewritten (by mod_rewrite in `.htaccess`). UNLESS you are processing the mod_security rule in the wrong `phase` during the Apache request (which could happen by _default_)? I've updated my answer. – MrWhite Sep 14 '18 at 21:31
  • That was my expectation too, but apparently it isn't the case. The modsec rule is in phase 2, and modsec's REQUEST_URI at that point contains the post-rewrite url. (I also tried the other phases in the course of testing, with no difference.) My understanding is that when a rewrite occurs Apache goes back through processing config from the beginning, so that could have something to do with it. – Nathan Stretch Sep 15 '18 at 03:53
  • On the other hand, if you set an environment variable in modsec phase 2, it is lost when the internal rewrite occurs (or actually, it is prepended with the REDIRECT_ prefix by apache), which suggests that that rule is being parsed pre-redirect. So that part is still a bit of a mystery to me. Will have to wait for another day though, since REQUEST_LINE does the job, and I have other work to move on to! – Nathan Stretch Sep 15 '18 at 03:54