REMO – Documentation


Main | Download | Documentation

Tutorial

There is a Remo tutorial at HowToForge: http://www.howtoforge.com/remo_modsecurity_apache

Rules

The ruleset generated by remo is a mod_security configuration set to be included with your apache configuration. It is a standalone ruleset, but you can also integrate it with the core ruleset as distributed by http://www.modsecurity.org

Standalone configuration

Save the ruleset next to your apache configuration. On a debian setup, /etc/apache2/rulefile.conf is a good place.

In your apache config, load the rulefile as follows:


<IfModule mod_security2.c>
Include /etc/apache2/rulefile.conf
</IfModule>

Core rule integration

Extract the inner part (from the first LocationMatch directive to the end) of the ruleset and integrate it as a custom rulefile with the core ruleset.

Ryan Barnett has made a blog entry on how to add custom rules to the core ruleset: http://www.modsecurity.org/blog/archives/2007/02/handling_false.html.

Ruleset Sections

The ruleset generated by remo has 3 Sections:

  • General configuration
  • Path rules
  • Fallback rule

So after a general configuration section, every path of the ruleset is defined serially: Path after path using the LocationMatch directive.

After all the paths, there is a fallback rule denying all the requests, that have not been covered by one of the path rules.

Ruleset path rules

The path rule is a rule defining access to a single URL path.

There are multiple sections:

* Method enforcement
The http method is checked and enforced (get, post, head, etc.)
* Strict headercheck
Only predefined headers are allowed. Requests with unknown headers are denied.
* Individual header mandatory check Check for the presence of the required headers. These are parameters marked as mandatory.
* Individual header validity check
Every header is checked for validity.
Note that the individual header is optional. This means, that a request does not have to send a certain header. But when it does, then it has to conform to the predefined regular expression.
* Strict cookiecheck
Only predefined cookies are allowed. Requests with unknown cookies are denied.
* Individual cookie mandatory check Check for the presence of the required cookies. These are parameters marked as mandatory.
* Individual cookie validity check
Every cookie is checked for validity.
Note that the individual parameter is optional. This means, that a request does not have to send a certain cookie parameter. But when it does, then it has to conform to the predefined regular expression.
* Strict querystringcheck
Only predefined query string arguments are allowed. Requests with unknown query string arguments are denied.
* Individual query string mandatory check Check for the presence of the required query string arguments. These are parameters marked as mandatory.
* Individual query string validity check
Every query string parameter is checked for validity.
Note that the individual query string parameter is optional. This means, that a request does not have to send a certain query string parameter. But when it does, then it has to conform to the predefined regular expression.
* Strict post parameter check
Only predefined headers are allowed. Requests with unknown headers are denied.
* Individual post parameter mandatory check Check for the presence of the required post parameters. These are parameters marked as mandatory.
* Individual post parameter check
Every post parameter is checked for validity.
Note that the individual parameter is optional. This means, that a request does not have to send a certain post parameter. But when it does, then it has to conform to the predefined regular expression.
* Fallback allow rule
If all the restriction rules are passed, then the request is given access.

Skipping within the ruleset path rules

When you add two or more requests with different http methods, but the same path, they will be handled within the same location match block. The blocks within the location match will be seperated via a skip-header and additional skip commands.

This means ModSecurity is being instructed to branch depending on the http method. This will result in quite a lot of skips. This has been introduced with remo version 0.1.4.

Individual rules

Remo helps to write positive security rules. This means you define good arguments in remo. ModSecurity uses this definition to tell the bad arguments from the good ones.

Have a look a the following scheme, which explains the transformation process.

Frequently Asked Questions

Or rather questions that might arise …

What is blacklisting and what is whitelisting?

Imagine a VIP club with a guard outside the door. There are two policies for the guard. Backlisting and whitelisting:

* Blacklisting: Do not let the bad guys named Jamie O., Sam Q. and Debbie S. in.
* Whitelisting: Only give permission to club members named Tom A., Jim G., Harry O., Walt C., Amanda B., John S., Peter D., Geoff F., Peggy H., etc.

The blacklisting approach is very simple. Give the names to the guard or provide him with photographs. Whitelisting is more difficult, as the list tends to be long and changing frequently.

The disadvantage of blacklisting is however, that you need to know the bad guys. A bad guy not on the list will get access easily.
With whitelisting, this won’t happen. You are sure you’ll only have club member in your club and as long as you can trust them, you are on the save side.

Traditionally firewalls work with a whitelisting approach: Everything is closed by default and specific traffic is allowed.

Application firewalls rather work with blacklisting these days. If you have a good and frequently updated set of rules (like ModSecurity core rules), this will help against all known attacks. However, there remains the problem of the unknown attacks. They will be able to slip in unnoticed like the unknown bad guys sneak into the bar.

Remo has a whitelisting approach. It writes rules, that close everything by default and then allow specific parameters to pass through, like the club members are given access to the bar.

How can I integrate a remo-ruleset with the core-rules?

It is easiest you set up your core rule apache and then generate the rules for every request seperately (there is a generate button next to every request). You save these rules for every request and include them into your core ruleset.

Here are infos about the ModSecurity Core Rules and this links to a blog entry explaining core rules customization.

Just what is the right way to define parameters (what do all these arguments mean)?

First you add a request, then you add the parameters to the request, one by one. There are four types of parameters per request:

* headers (there is a default set of headers for every header)
* cookie parameters
* query string parameters
* post parameters

If you know your application well, then you should be able to fill these in without a problem. Otherwise you can generate a full ModSecurity audit log of your application in practice and import that one into Remo and then walk through the requests and see if they are covered by your ruleset.

Every parameter has the following arguments:

* Name
* Domain
* Mandatory/optional flag
* Custom regex
* Status code (failed domain match)
* Location (failed domain match)
* Status code (failed mandatory condition)
* Location (failed mandatory condition)

Name is the name of the parameter. This is click-to-edit by default and can be edited only once. If you mistype the name, then remove it and add a new parameter.

Domain is a drop down select value. It is click-to-edit by default. You can select one of the default domains in the list. If you select Custom, then can define a custom regular expression in the detail block of the parameter. The default domains are explained futher down below.

Mandatory/optional flag indicates if a parameter has to be present (required parameter) or if it is an optional parameter. Click on the link to toggle the flag.

Custom regex is the domain pattern that comes into play, when Custom is selected as the domain value. This value is part of the detail block that is closed by default. You have to open the block first.

Status code (failed domain match) is the status code that is being returned when the domain pattern is not matched. It is Default by default.

Location (failed domain match) is the location value when a redirect is issued. This means you select a redirect status code like 301 in the previous field and then this is taken as the redirect target.

Status code (failed mandatory condition) is the status code that is being returned when this mandatory parameter is missing. It is Default by default.

Location (failed mandatory condition) is the location value when a redirect is issued. This means you select a redirect status code like 301 in the previous field and then this is taken as the redirect target.

How can I define other default headers?

The default headers are defined in remo_config.rb.

How can I change the default value domains of the default headers?

The default headers are defined in remo_config.rb. You can define the default values there too.

Does remo support dynamic parameter names as they are frequently used in forms?

Yes, remo supports these, thanks to ModSecurity, which has support for regular expressions in argument names.

Say your parameters are names user_1, user_2, … or theme[bluecoat], theme[pinksheet] etc.

Then you can define these as

* user_\d
* theme\[[a-z]{1,12}\]

The second example demands a bit of regex knowledge. It means we want theme, then a rectangular bracket, then 1 to 12 letters from a to z (no capitals here), finally the closing bracket.

You may have to play around a bit to get used to the concept.

How can I handle an URL that can be accessed via GET and via POST (as an example)?

You can define two requests with the same path, but different methods. Remo will then cover them inside the same location match block, but divide them using skip blocks.

How can I treat a missing parameter that is mandatory in a special way?

Say a request lacks a sessionid cookie and you want to redirect the user to the login page.

Define the sessionid cookie paramter, set it to mandatory and access the parameter details.
There you can fill out the two values: Status code (failed mandatory condition) and Location (failed mandatory condition).

For a redirect, set the status code to 301 and the location to i.e. /login.html.

How can I treat a certain paramter failing to match the domain pattern in a special way?

Say you respond with http status code 501 to every request, that fails to meet the conditions of the ruleset. But on a certain failure, you want to respond with http status code 404.

Define your parameter and acccess the parameter details. There you can fill out the the value Status code (failed domain match).

Simply set it to 404. If you want to do a redirect instead, set it to 301 and fill out the Location (failed domain match) value.

How can I change the default http status code for requests that were denied access?

You can edit the value HTTP_DEFAULT_DENY_STATUS_CODE in remo_config.rb.

My ruleset is growing and remo gets slower and slower

When opening remo in your browser, the whole ruleset gets loaded in a single request. A ruleset with ten different URLs (note that these can be regular expressions, so fairly complex application can fit in half a dozen URLs) can take up to a minute to load. Half of the time is the time the server needs to build the html page, half of the time is taken by the browser attempting to display the html. A ruleset quickly expands over 2MB in html size and this takes time to load.

After you have loaded the ruleset, working in the browser is fairly straight forward thanks to ajax and the partial requests carried out.

There are plans to improve the performance of remo after the beta release, but it is quite tricky to do this in a successful manner.

I am puzzled. What is the right way to work with Remo? Is there a best practice work-flow?

It is best to start with an empty rulebase in the rulearea on the right and then proceed in an iterative cycle:

* Enter a few requests and a few parameters.
* Generate the ruleset and install it. If you have it is best to use a test-machine for this.
* Use your application a bit (you are likely to meet many errors, as your ruleset does not cover all requests so far)
* The ruleset will generate an audit-log. Import that one into the Remo logfile-area.
* Walk through the requests in the logfile-area and see if they are covered by the ruleset.
* Restart above and add the requests that failed accoring to your logfile.

Do this as long as there are failing requests. When all the requests work and you are sure, you tried it all, then your ruleset is done and you can put it in practice.

There is a tutorial at howtoforge, using this workflow: http://www.howtoforge.com/remo_modsecurity_apache

Frequently used regular expressions – the default domains

Every parameter checked by a remo-generated ruleset is matched against a certain pattern. The pattern guarantees, the parameter is part of a closely defined value-domain, short domain. Some of these domains are frequently used; they are thus predefined in remo as default-domains.

You can add more default domains or change these values in remo_config.rb.

Hostname

[0-9a-zA-Z-.]{1,64}

IP Address V4

The following regular expression matches every IPV4 address. Note that the numbers are not limited to 255. So we are strict on the pattern, but not on the numbers themselves.

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

IP Address A6

The following regular expression matches every IPV6 address.

([0-9a-fA-F]{4}|0)(\:([0-9a-fA-F]{4}|0)){7}

Base64, 16 character limit

A base64 encoded string, limited to 16 characters.

[0-9a-zA-Z+/]{0,16}={0,2}

Integer, 16 character limit

\d{0,16}

Flag only (none)

The parameter is only a flag. You may not provide any parameter. (i.e. a request like http://remo.netnea.com/index.php?uid=42&verbose. Verbose is a flag in this example)

\w{0}

This is a pattern of characters with a strict length of 0.

Sessionid, alphanumerical characters, max 16 characters

[0-9a-zA-Z]{1,16}

Username

This limits a username to letters, digits, underscore, hyphen and backslash with a maximum of 32 characters.

[0-9-a-zA-Z_-\]{0,32}

User-Agent header

This is not throughly tested so far. If you have any issues regarding this value, please report them.

[0-9a-zA-Z +:;!()/.-]{1,256}

Host Header

[0-9a-zA-Z-:.]{3,64}

Basic Authorization Header

The Basic Auth header should match the following regular expression, according to RFC 2617 (http://rfc.net/rfc2617.html#p5)

Basic\s[0-9a-zA-Z+/]{0,256}={0,2}