Wednesday, June 17, 2009

Open Source Application Layer Firewall part 5

Continuing with our discussion of setting up a home-grown application layer firewall. So far we have set up an insecure application that needs protection. Then we configured our server to act as a router. Then we set up stateful packet inspection using PF, and turned it into a proxy firewall using Apache. Now I'd like to talk about how you can really look deep into the application traffic to stop unauthorized activity at a much higher level than what is possible with a stateful inspection firewall.

Now that we have a proxy firewall, we want to set up Apache mod_security to look deep into our http requests and identify malicious traffic. We're going to use packages to install mod_security, so the first thing we should do is set up our package path. I'm going to use the main OpenBSD distribution site for this, but you should probably choose a mirror that is closer to you. First we want to set up the environment variable:
# export PKG_PATH=

You can also add this to your .profile file so that you will have that set up every time the machine boots.

export PKG_PATH

Now we can search the package list for mod_security.

# pkg_info -Q modsecurity

And then install it:

# pkg_add modsecurity-apache-1.9.3p2
modsecurity-apache-1.9.3p2: complete
--- modsecurity-apache-1.9.3p2 -------------------
To finish the install of modsecurity-apache-1.9.3p2, you need
to enable the module using the following command


The manual is found at /usr/local/share/doc/mod_security.

If you already have Apache running on your machine,
you should not use "apachectl restart" - instead,
you should fully stop and then start the server.
# /usr/local/sbin/mod_security-enable
Enabling module...
[activating module `security' in /var/www/conf/httpd.conf]
cp /usr/local/lib/ /usr/lib/apache/modules/
chmod 755 /usr/lib/apache/modules/
cp /var/www/conf/httpd.conf /var/www/conf/httpd.conf.bak
cp /var/www/conf/ /var/www/conf/httpd.conf
rm /var/www/conf/

Let's follow the directions and shut down the httpd server:
# apachectl stop
/usr/sbin/apachectl stop: httpd stopped

Now take a moment to examine our httpd.conf file. You will notice that one line has been added to the configuration by the mod_security-enable script
# diff httpd.conf httpd.conf.bak
LoadModule security_module /usr/lib/apache/modules/ #

Now that we have mod_security set up in Apache, let's do something with it. I'm going to put together a basic set of options, and put in one single filter that will block any requests going to my server that have the word "kevin" in them. Open up /var/www/conf/httpd.conf and enter this into one of the VirtualHosts that we created earlier.
 SecFilterEngine on
SecFilterCheckURLEncoding On
SecFilterScanPOST On
SecAuditEngine On
SecAuditLog /var/www/logs/audit_security.log
SecFilterDefaultAction "deny,log,status:500"
SecFilter "kevin"

The indenting is not necessary, but it makes it look good and helps to identify all of the mod_security related stuff in this virtual host. You can also put configuration directives like this in the global configuration rather than within a single VirtualHost. However, if you're going to have multiple servers behind this firewall, you may find that you need different rules for each one, so I'm going to do it this way. Restart httpd to make the changes take effect.

Now let's test it. I'm going to go to my web application and enter the following:
Firstname: Shamus
Lastname: McFinnigan
Card: some number
I hit submit and the application works as expected. Then I tried the same thing but with the first name kevin instead. Mod_security blocked the request, and gave me an http 500 error. Mod_security is working. Congratulations, you now have a firewall that is doing layer 7 inspection of your traffic before it hits the server. You have an application layer firewall.

The rule set that we've built in here doesn't really do much for us, unless we want to discriminate against the Kevin's of the world. But what if we were using this to protect some appliance and we didn't know whether or not the coders had put proper input validation into their form fields? Well one thing we could do is use our proxy server to look at the requests that go by and find out what variable names are in use, and then write filter rules. For example, I know that my crappy application should only accept First and Last names that are alphabetical characters and no more than 12 characters in length. I also know that credit card numbers should only contain digits and dashes and that there should be four digits followed by a dash. So I can take out my SecFilter Kevin line and replace it with this:
SecFilterSelective "ARG_Fname" !^([A-Z]|[a-z]){1,12}$
SecFilterSelective "ARG_Lname" !^([A-Z]|[a-z]){1,12}$
SecFilterSelective "ARG_Ccard" !^([0-9]{4}-){3}[0-9]{4}$

So from the first name variable we're going to filter anything that does not match our regular expression (!). The regular expression indicates that we want to start with the first character of the variable (^) and that it should be an uppercase or lowercase letter ([A-Z]|[a-z]). That should occur at least one time but no more than 12 times {1,12} and then there should be nothing else $.

So now, regardless of how crappy the application behind the firewall is, it is protected pretty well. Sure it's not going to be bullet proof, but adding in this kind of input validation will add a lot of strength to your application security. Try doing this with a Cisco ASA box.

Check out the rules at for more ways to strengthen your box. I suggest adding these in one at a time and making sure that your apache process doesn't crap rather than putting in the whole wad. Also, ff making up your own rules seems difficult, try out this online rule creator!

What about the core rule set?
Yeah, that would be pretty cool, wouldn't it? Well it's not going to happen anytime soon, at least not the way I've set things up here. One of the things I've tried to do in this setup is leverage the work of other people that are smarter than me to make a good firewall. One of the big points is using the chrooted Apache software that comes with OpenBSD. In order to use th mod_security core rule set, you have to be running Apache2. The core rule set depends on a newer version of mod_security, and that version depends on Apache2. Installing Apache2 on OpenBSD is pretty easy, but it isn't chrooted which means you have to do all that work yourself. I'd like to start working on another version of this that uses a chrooted Apache2, but first I need to figure out how to do that and keep it secure.

No comments: