Three ModSecurity Rule Language Annoyances
There are three aspects of the ModSecurity Rule Language we are not very happy with. One comes from a wrong design decision (my own), with further two from constraints of working within the framework of Apache. All three break the principle of the intuitive action being the expected one. I am going to document them here and explain how we are planning to mitigate them in future versions:
- In a chain starter rule, disruptive actions are processed when the chain matches, but non-disruptive actions are processed when the rule matches. In other words, it is only the disruptive actions that are treated differently in chains, all other action types behave as they would in standalone rules. Have a look at the following:
SecRule T1 K1 chain,log,block,setvar:tx.counter=+1
In the example above the counter will be incremented if the first rule matches even if the chain doesn't. The blocking action, although defined with the same rule, would only be processed if both the first rule and the second rule match.
SecRule T2 K2
In retrospective, disruptive actions for chains should have been placed with the last rule in a chain, not with the first one. If it is possible to move to that mechanism in the next major version while preserving compatibility with existing configurations we will do that.
SecDefaultActionis valid only for the configuration context in which it is used and is not inherited in child contexts. Configuration contexts are an Apache feature and they come with limitations, one of which is causing this problem.SecDefaultAction log,deny
In the above example, the first rule blocks, but the second one just uses the ModSecurity defaults and only warns and lets requests through.
SecRule T1 K1
<Location /some/other/path>
SecRule T2 K2
</Location>
In the next major version of ModSecurity (v3) we will handle our configuration ourselves and this problem will probably go away. In fact, theSecDefaultActiondirective might be made obsolete in the next major version because we don't like it much. In retrospective, it was a wrong choice too. It is good practice to write rules to be self-contained. That way they will be easier to understand and maintain, and you don't risk configuration errors due to something being changed in the configuration elsewhere.
- Configuration contexts other than
<VirtualHost>cannot hold phase 1 rules. Again, this is a limitation of the current implementation that relies on Apache for configuration functionality.
Short term (e.g. 2.6), we are planning to see if we can detect phase 1 rules in places where they cannot be run and respond with an configuration error. The problem will go away once we start handling our own configuration.

SecDefaultAction may be very valuable for global settings, like sanitizing Authentication header, or redirecting to a standard page
Posted by: Marc Stern | 24 July 2008 at 07:49 AM
Nice post Ivan.
I won't miss SecDefaultAction if it goes away, but Marc Stern may have a point. What I do not like about it is rather the way it is handled. It appears in many tutorials and online examples, so people start to mess with it. I would prefer it to be an advanced setting for experienced users (and advertised as such).
Posted by: Christian Folini | 24 July 2008 at 09:58 AM
I do agree that some of the functionality currently provided by SecDefaultAction deserves to day, but we need to find a way to do it in a way that will promote good practices.
Posted by: Ivan Ristić | 24 July 2008 at 10:46 AM
What about the other settings, like SecAuditLogParts, SecCacheTransformations, etc. ?
Are they all inherited ?
Hey, it seems we always see the same guys here ;-)
Posted by: Marc Stern | 25 July 2008 at 03:12 AM
As far as I can remember, SecDefaultAction is the only directive that is not inherited. That's because it is also the only directive that can be used several times within the same configuration context.
Posted by: Ivan Ristić | 25 July 2008 at 04:05 AM