작성자 : Victor Julien
출처 : http://www.inliniac.net/blog/2007/03/01/update-on-using-realtime-blacklists-with-modsecurity.html

아래 글에서는 wordpress의 코멘트쓰기 트랙백 스팸검사를 위해 rbl(realtime blacklist)
검사를 하지만 다른 프로그램들도 응용이 어렵지 않을것같습니다.

----------------------------------------------------------------------------------

Update on using realtime blacklists with ModSecurity
Thursday, March 1st, 2007
A few days ago I posted a blog article about stopping comment spam with ModSecurity using realtime blacklists (rbl). While the approach was working, I noted having problems with rules when I tried to match on POST methods in HTTP requests.

Luckily, ModSecurity creator Ivan Ristic was quick to point out where the problem is. I’m using the Core Ruleset for ModSecurity, and one thing that ruleset does is use the ‘lowercase’ transformation. This converts all text from arguments to lowercase, so my ^POST$ match would never be able to match. So like Ivan suggested, using ^post$ solved this part.

Next Ivan pointed out a weakness in the rules. My rules looked for /blog/wp-comment-post.php, and would be easily evaded by just using /blog//wp-comment-post.php. He suggested using the ‘normalisePath’ transformation. I did this, but I also slightly changed the rules to not look for the /blog/ part at all (maybe this makes normalisePath useless, but I decided to rather be safe than sorry).

The rules I’m using now look like this:

SecRule REQUEST_METHOD "^post$" "log,deny,chain,msg:'LOCAL comment spammer at rbl list.dsbl.org'"
SecRule REQUEST_URI "wp-(comments-post|trackback).php$" "chain,t:normalisePath"
SecRule REMOTE_ADDR "@rbl list.dsbl.org"

SecRule REQUEST_METHOD "^post$" "log,deny,chain,msg:'LOCAL comment spammer at rbl bl.spamcop.net'"
SecRule REQUEST_URI "wp-(comments-post|trackback).php$" "chain,t:normalisePath"
SecRule REMOTE_ADDR "@rbl bl.spamcop.net"

SecRule REQUEST_METHOD "^post$" "log,deny,chain,msg:'LOCAL comment spammer at rbl sbl-xbl.spamhaus.org'"
SecRule REQUEST_URI "wp-(comments-post|trackback).php$" "chain,t:normalisePath"
SecRule REMOTE_ADDR "@rbl sbl-xbl.spamhaus.org"

Thanks a lot Ivan Ristic for your comments!

출처 : http://www.onlamp.com/pub/a/apache/2003/11/26/mod_security.html
modsecurity 1.x 대버전과 2.x버전대의 syntax가 많이 달라졌습니다.
1.x대의 rule을 2.x대에 그대로 적용할수 없으니 관련 문서를 읽어보시고 적용하시기 바랍니다.
http://www.modsecurity.org/documentation/index.html
Introducing mod_security
by Ivan Ristic
11/26/2003
Running public web applications may seem like playing Russian roulette. Although
achieving robust security on the Web is possible in theory, there's always a
weak link in real life. It only takes one slip of the code to allow attackers
unrestricted access to your data. If you have a public web application of modest
complexity running, chances are good that is has some kind of security problem.
Take this URL for example:
http://www.webapp.com/login.php?username=admin';DROP%20TABLE%20users--
If your application is vulnerable to SQL injection, invoking the URL above may
very well delete all user data from your application. Do you make regular
database backups?
Fortunately, the mod_security Apache module can protect you from this and other
forms of web attacks.
Why Would You Use mod_security?
A year and a half ago, before I started working on mod_security, I used Snort to
monitor my web traffic. It worked very well; I told Snort which keywords I was
interested in and it alerted me every time one appeared in the data stream. But
I wanted more. I wanted the freedom to specify complex rules and perform various
HTTP related actions. Besides, having an IDS installed wherever a web server
exists is very time consuming and expensive.
At the time I also tried the combination of mod_rewrite and mod_setenvif. Using
mod_rewrite it is very easy to detect the words drop and table, and then
redirect the client away from the original URL, preventing the attack. However,
while that would certainly keep away less knowledgeable attackers, a determined
attacker could simply invoke the same URL as above but use the POST method
instead of GET. Since POST variables are not considered in the normal processing
of most modules, the attack would go through.
Having established the need to build a new tool, I faced two choices: go with
Java and create a full-blown reverse proxy and application gateway application,
or create an Apache module, building on top of a large amount of existing code.
Option one would require a lot of work and probably result in something very few
people would want to use (hey, I wouldn't use it either). I wanted to build
something flexible and easy to use, so I chose the latter. I've never looked back.
Going back to our URL example, to prevent the "drop table" SQL injection attack
with mod_security, add the following to your Apache configuration:
SecFilter "drop[[:space:]]table"
The only parameter is a regular expression to be applied to the incoming
request. This seems achievable with mod_rewrite, but the difference here is that
mod_security will detect and prevent attacks performed using either GET or POST.
As it turns out, adding the ability to monitor POST requests was a very big
problem for Apache 1.3.x since it does not support a notion of filters.
Installation and Configuration
The best way to install mod_security is to compile it from the source code (or,
if you are running Apache on Windows and don't have a compiler around go to the
web site and download a pre-compiled dll):

$ /path/to/apache/bin/apxs -cia mod_security.c
# /path/to/apache/bin/apachectl stop
# /path/to/apache/bin/apachectl start
Before you do that you need to add few lines to the configuration file:

<IfModule mod_security.c>
# Turn the filtering engine On or Off
SecFilterEngine On
# Make sure that URL encoding is valid
SecFilterCheckURLEncoding On
# Unicode encoding check
SecFilterCheckUnicodeEncoding Off
# Only allow bytes from this range
SecFilterForceByteRange 0 255
# Only log suspicious requests
SecAuditEngine RelevantOnly
# The name of the audit log file
SecAuditLog logs/audit_log
# Debug level set to a minimum
SecFilterDebugLog logs/modsec_debug_log
SecFilterDebugLevel 0
# Should mod_security inspect POST payloads
SecFilterScanPOST On
# By default log and deny suspicious requests
# with HTTP status 500
SecFilterDefaultAction "deny,log,status:500"
</IfModule>
I've left the comments in the code so it should be pretty evident what
directives do. This configuration will activate mod_security but it won't do
much. It is always a good idea to start with a relaxed configuration and build
into a more restrictive one.

So What Does this Do?
Even with the relaxed configuration, mod_security will still provide two
benefits. First, it will perform a series of anti-evasive techniques and will
canonicalize the input. This will help later when you start adding filtering
rules to the configuration. Imagine you want to prevent people from executing a
ps binary on the server, using a regular expression such as /bin/ps ax. This
expression would catch simple invocations but perhaps not /bin//ps ax or
/bin/ps%20ax or /bin/./ps ax. Here is a list of what mod_security does here:

* Remove multiple forward slashes (//).
* Remove self-referenced directories (./).
* Treat and / equally (on Windows only).
* Perform URL decoding.
* Replace null bytes (%00) with spaces.
I am also thinking about replacing all consecutive white space characters with
spaces, but I am not yet sure about it.
The other benefit comes from certain built-in checks:
* URL encoding validation.
* Unicode encoding validation.
* Byte range verification, where only certain character values are allowed
as part of a request.
Actions
Whenever a rule match occurs a series of actions is performed. The default
action list (configured through SecDefaultAction) is used in most cases. It is
also possible to specify per-rule actions by supplying a second parameter to
SecFilter or a third parameter to SecFilterSelective. Supported actions are:
* deny, deny the request
* allow, stop rule processing and allow the request
* status:nnn, respond with a HTTP status nnn
* redirect:url, redirect the request to the absolute URL url
* exec:cmd, execute a script cmd
* log, log the request to the error log
* nolog, do not log the request
* pass, ignore the current rule match and go to the next rule
* pause:nnn, stall the request for nnn milliseconds. Be very careful with
this action; one Apache instance will be busy stalling the request. You could
actually help the attackers in creating a denial of service attack.
Other actions affect the flow of the rules, similarly to how mod_rewrite works:
* chain, go to evaluate the next rule in the chain. When one rule fails to
trigger an alert the remaining rules from the chain will be skipped.
* skipnext:n, skip the next n rules.

Filtering Rules
Rules come in two flavors. In the simplest form,
SecFilter keyword
will apply the keyword (a regular expression) to the first line of the incoming
request (the one that looks like GET /index.php HTTP/1.0) and to the POST
payload if it exists. It is a pretty broad rule whose purpose is mostly to be
used as a first step when rules are introduced in articles like this one. You
should instead use:

SecFilterSelective "variable list separated with |" keyword
as it allows much better control over what should be analysed (and spends less
CPU cycles doing it). Instead of continuing to bore you with the syntax I will
now present a series of interesting examples. Let them serve as inspiration; the
most useful rules usually come from dealing with real-world problems.

This rule will allow all requests from a single IP address (representing my
workstation) through. No other rules will be processed. Since such requests do
not represent attacks this rule match will not be logged:

SecFilterSelective REMOTE_ADDR "^IP_ADDRESS_HERE$" nolog,allow
This rule allows me full access from my laptop when I am on the road. Because I
don't know what your IP address will be, access is granted to all clients having
a string Blend 42 in the User-Agent field. This is poor protection on its own
but can be pretty interesting on top of some other authentication method.

SecFilterSelective HTTP_USER_AGENT "Blend 42"

This rule prevents SQL injection in a cookie. If a cookie is present, the
request can proceed only if the cookie only contains one to nine digits.

SecFilterSelective COOKIE_sessionid "!^(|[0-9]{1,9})$"

This rule requires HTTP_USER_AGENT and HTTP_HOST headers in every request.
Attackers often investigate using simple tools (even telnet) and don't send all
headers as browsers do. Such requests can be rejected, logged, and monitored.
SecFilterSelective "HTTP_USER_AGENT|HTTP_HOST" "^$"

This rule rejects file uploads. This is simple but effective protection,
rejecting requests based on the content type used for file upload.
SecFilterSelective "HTTP_CONTENT_TYPE" multipart/form-data

This rule logs requests without an Accept header to examine them later; again,
manual requests frequently do not include all HTTP headers. The Keep-Alive
header is another good candidate.

SecFilterSelective "HTTP_ACCEPT" "^$" log,pass
This rule will send me an email when the boss forgets his password again. We
have two rules here. The first will trigger only when one specific file is
requested (the one showing the "Login failed" message. The second rule will then
check to see if the username used was ceo. If it was, it will then execute an
external script.

SecFilterSelective REQUEST_URI "login_failed.php" chain
SecFilterSelective ARG_username "^ceo$" log,exec:/home/apache/bin/notagain.pl
This rule sends Google back home by redirecting Googlebot somewhere else, based
on the User-Agent header. It does not log rule matches.
SecFilter HTTP_USER_AGENT "Google" nolog,redirect:http://www.google.com
This rule checks all variables for JavaScript, allowing it in a variable named
html. Disallowing JavaScript in all variables can be very difficult for some
applications (most notably CMS tools). By using this rule we disallow JavaScript
in all variables except in the one named html, where we know it can appear.
SecFilter "ARGS|!ARG_html" "<[:space:]*script"
Finally, this example shows how you can have multiple mod_security
configurations. This means you can tailor rules for a specific application. Note
the usage of the directive SecFilterInheritance. With it we tell mod_security to
disregard all rules from the parent context and start with a clean slate.
<Location /anotherapp/>
SecFilterForceByteRange 32 126
# Use this directive not to inherit rules from the parent context
SecFilterInheritance Off
 # Developers often have special variables, which they use
# to turn the debugging mode on. These two rules will
# allow the use of a variable "debug" but only coming from
# the internal network
SecFilterSelective REMOTE_ADDR "!^192.168.254." chain
SecFilterSelective ARG_debug "!^$"
</Location>

Performance Considerations

I have never had any performance problems with mod_security. In my performance
tests the speed difference was around 10 percent. However, the practical
performance penalty is smaller. On real web sites, a single page request may
provoke many static requests for images, style sheets, and JavaScript libraries.
Mod_security is smart enough not to look at those only if you tell it not to:

SecFilter DynamicOnly

The bottleneck is always in the IO operations. Make sure that the debugging mode
is never turned on on a production server, and avoid using the full audit
logging mode unless you really need to. In the configuration above, mod_security
is configured to only log relevant requests, e.g., those that have triggered a filter.
Other Features
Internal chroot

If you have ever tried to chroot a web server you probably know that it is
sometimes a complex task. With mod_security the complexity goes away. You are
one configuration directive away from a chrooted server:
SecChrootPath /chroot/home/web/apache

The only requirement is that the web server path in the chroot be the same as
the path outside of the chroot (in the example above, /home/web/apache). In
addition to making chrooting very easy, this approach will allow you to have a
chroot that contains only data files without binaries. This advantage comes from
the fact that the chroot call is executed internally, after all the dynamic
libraries are loaded and log files opened.
Changing Server Signature
Attackers and automated scripts frequently learn about the server and the
version from the "Server" HTTP header that is delivered with every response. You
can change only change this by changing the Apache source code, but you can also
use this directive. (You should use this feature only if you're running Apache
1.x. Module mod_headers included with Apache 2.x should be able to intercept
outgoing headers, and change them on the fly):
SecServerSignature "Microsoft-IIS/5.0"

What Next?

Although I compared mod_security to Snort at the beginning of this article,
mod_security is just another tool in your security belt. It works best together
with an IDS operating on a network level. Its biggest advantage is in filling
the gap between the web server and the application, allowing you to protect your
applications without actually touching the source code.

While you are reading this article I am busy working on a couple of new and very
interesting features. First of all, I want to complete multipart/form-data
encoding support. Once that is done, you will be able to intercept file uploads
and run checks on files (using external binaries), with an option to reject them
for any reason. Even more interesting is a feature called a "Application
Armour," a special form of application lockdown where for each script you will
be able to specify and verify every incoming parameter (you won't need to do it
manually, don't worry).

In the meantime, please send me your comments and requirements to influence the
way mod_security develops.
References
* mod_security
* Snort
Ivan Ristic is a Web security specialist and the author of mod_security, an open
source intrusion detection and prevention engine for web applications.

+ Recent posts