A defensive approach to web application security generally relies on onion architecture: it consists of several layers of defence. One of those layers is often a web application firewall (WAF), of which there are many different commercial offerings in this space. Yet, there is only a single general-purpose open source WAF: ModSecurity bundled with the OWASP Core Rule Set (CRS). In this setup, ModSecurity is the engine and CRS brings the rules that detect the malicious traffic.
CRS aims to protect services against the security risks described in the OWASP Top Ten document. However, even a well-integrated WAF is not the end of all security problems as the protection will always be incomplete. Vulnerabilities should still be fixed in the source code, but, ModSecurity / CRS can help with mitigation and they will buy some time while the attackers try to bypass the rule set. Ultimately, attackers can work around a WAF, but they usually give up and look for easier prey, especially if the rule set is tight and configured correctly.
The Core Rule Set
Let's look an example of a CRS rule: various SQL servers decode and execute hex-encoded queries. Hex-encoded payloads are thus a good entry point for SQL injection attacks, which is why CRS has a rule that detects a hex-encoded payload and flags it as a potential attack. This is a heuristic approach. Of course, not all hex-encoded payloads are attacks; sometimes you cannot even be sure something is hex-encoded or just looks that way. So, in real life, there is always the chance of a false alarm: a false positive of the detection mechanism.
A typical example in this regard, are session cookies: web applications use cookies to identify users by assigning their browser session a random string as a token. The browser will then submit this identification string with every request. This allows the application server to link the request to a session.
Many applications generate random session identifiers in a way that does not raise suspicion (e.g. simple ascii strings without any "0x"). But there are applications that use the full alphabet and the numbers 0-9 for session identifiers. So, there is some chance that the token string will contain "0x" followed by some hexadecimal numbers. The rule watching out for hex-encoded payloads will score a hit and raise an alert - a false positive.
Raising the Paranoia level
If an application exhibits this trait, the rule should be disabled for the session cookie. No big deal, but manual intervention is required nonetheless, which is why this rule is not enabled by default. In fact, the rules come in four groups based on their likeliness to trigger false positives.
Each of the groups defines a different Paranoia Level (PL). The default is Paranoia Level 1 (PL1). It contains only rules that are known to have a high detection ability while causing only a minimal number of false positives. That's a set of 150 rules.
At Paranoia Level 2 is hex-encoding detection and an extra set of 30 rules that are more aggressive or sensitive and cover more attacks; effectively raising the security level. But the system will likely receive a few false alarms in return, so the security comes at a price. The standard procedure is to look at these false positives and write so-called rule exclusions that are used to skip a rule under certain conditions.
Raise to PL3 to get another 15 rules as well as several more false positives. At PL3, one becomes rather proficient at handling false positives!
Finally, raising to PL4 reaches the greatest level of paranoia. Here, half a dozen extra rules leap on anything that does not look totally innocent. PL4 defines a small range of byte values it accepts in a request body. Every file upload and most special characters outside of letters and numbers will provoke an alert. Yet, reconfiguring the WAF to work around these false alarms, results in a very efficient way of protecting an application. The special characters are limited to the places where they are elementary for the correct working of the online application.
A definition of the byte range is also present in PL1, PL2, and PL3, but it is much laxer. Every new PL adds more rules that restrict the character set more and more: think of it as a relaxed base rule and a set of stricter siblings.
The Paranoia Levels are meant to be mapped to the security level of a site. A private blog does not have the same resources to put into security that a site processing credit card data does. Ideally, a security officer will assign a certain Paranoia Level to a service in the design phase. This will avert the integrators of the number of false positives waiting for their tuning intervention.
The commercial competition
Web application firewalls are a highly contested area with many commercial contenders. When inspecting the offerings, it is often surprising that quite a few of those appliances or cloud services are re-packaged ModSecurity / CRS combinations; or CRS running on top of a custom implementation of the ModSecurity rule language, optimised for specific purposes. That is fair game, but not all commercial vendors are transparent about their technology.
What commercial offerings often bring is an easier web user interface. The naked ModSecurity / CRS lacks this. Instead, it must be configured by hand. Traditionally, this has been very difficult, giving the solution a bad name. However, the CRS 3.0 milestone release in 2017 changed the situation. It came with a much-streamlined installation and configuration procedure. The feedback has been very positive and the user base has been growing ever since.
One of the reasons for this is the flexibility of the technology. Here, the lack of a standard graphical user interface becomes a virtue. ModSecurity / CRS allows for very easy integration of a WAF into the continuous integration / continuous development pipeline of an agile software development team.
The ideal setup comes with a large number of unit tests. They are executed the moment the developer commits their code. In fact, they are executed twice: once against the application directly and once across the WAF. If the unit test passes the direct test, but fails at the WAF, then a false positive has been discovered.
In this situation, the developer should either change the behaviour of the application or solve the false positive in the configuration of the WAF. This is performed by disabling the offending rule in this specific situation. This configuration change will then also be applied in production, together with the new source code. This setup gives the developer fast feedback which includes the WAF and reduces the risk to encounter new false positives in production.
Automatic security scanning
Once the setup is in place, it makes sense to do automatic security scanning as well. Here, a security scanner (like the free OWASP ZAP) looks for vulnerabilities in the committed code of the application. It is mandatory that no known issues are allowed into production. Both the code running exposed to the scanner and the code protected by the WAF have to be free of security problems. This way, the developers at least get the assurance that problems that can be detected automatically will be absent from the code. The code is thus basically ready for production from a security standpoint.
In conclusion
The ModSecurity / CRS WAF is a well-established and widespread open source solution. It is one of the best known OWASP projects; even if though the first steps may look a bit difficult, users are getting up to speed quite fast. It is, therefore, one of the most cost-effective ways to add a security layer to your web application services.