People can reach my webserver in three ways: by my domain inliniac.net, by the hostname connected to my dsl, and by my ipaddress. What i now wanted is setup the proxy in such a way, that only people visiting inliniac.net would be proxied to the webserver.
Blocking requests that are IP based instead of name based have an important advantage. IP based requests are mostly used by scantools and other forms of malicious traffic that just attempt connecting to port 80 on large IP-ranges. So this way one should be able to keep a lot of crap like worm traffic out.
Implementing this turned out to be a little more complicated than i thought. Essentially the only way i got it working was by creating three virtual hosts and put the proxy configuration in the virtual host for inliniac.net. The other two virtual hosts just deny access, so visiting them gives a 403.
Willam Metcalf told me that the server signature rewrite function from ModSecurity does not hide the original server signature in all cases. In normal 200 and 300 series responses, the original signature is still in the header. Enabling the ‘header’ module and adding this to your config, helps:
Header set Server “Apache”
This way people will know you run Apache, but won’t know which version.
Another nice feature of ModSecurity is rule based redirection. Lets say i want to block visitors of my website from opening the login page of wordpress, /blog/wp-login.php. I could of course just deny access to it, so the visitor gets a 403 error. This works fine, however sometimes you might want to use a more userfriendly message, for example: ‘Due to maintainance logins are currently disabled’.
To do this i first created a very simple html file called nologin.html, and placed it in the webroot of the server. Then i added the following rules to Mod_Security:
# block wp-login.php
SecFilterSelective REMOTE_ADDR “!192.168.1.2” chain
SecFilterSelective REQUEST_URI “/wp-login.php” log,deny,redirect:http://www.inliniac.net/nologin.html
These rules check first if the ipaddress is not 192.168.1.2, then look for /wp-login.php in the URI. If it is found, the request is logged and blocked. The server then sends a redirect 302 response to the client which will open the nologin.html page. Since the original request is blocked, the webserver behind the reverse proxy never sees the request.
Ok, that’s a bit misleading, because i’m not just hiding, but also blocking and logging. What i wanted is this: I’m running awstats on my reverse proxy, but i don’t want anyone to know. So i just made the entire ‘cgi-bin’ part forbidden for everyone, so that covers the script. The fact that my webserver has a cgi-bin directory is nothing special and won’t tell you i’m using awstats. However, awstats also uses icons, and these are by default in /awstats-icon/
Now, i could have made that restricted as well, but that still would give you the information that it exists! ModSecurity to the rescue. I want only access to awstats from my workstation, so i added these rules:
SecFilterSelective REMOTE_ADDR “!192.168.1.2” chain
SecFilterSelective REQUEST_URI “/awstats-icon/” log,deny,status:404
These say: if the ipaddress of the visitor is not 192.168.1.2, and his request contains /awstats-icon/, we log it, block it, and send back a 404 error. This makes the visitor think the directory doesn’t exist on the server.
I’m not sure how easy this can be extended to giving an entire subnet access though, maybe i’ll investigate this later.
A few weeks ago i wrote that i wanted to investigate setting up a reverse web proxy with mod_security. I have now finally found a little time to do so. What surprised me was how easy it actually is!
#turning ProxyRequests on and allowing proxying from all may allow
#spammers to use your proxy to send email.
Allow from all
#Allow from .your_domain.com
# Enable/disable the handling of HTTP/1.1 “Via:” headers.
# (“Full” adds the server version; “Block” removes all outgoing Via: headers)
# Set to one of: Off | On | Full | Block
# use to disable proxy for a specific subdir
# ProxyPass /blog/wp-admin !
ProxyPass /blog http://internalserver/blog
ProxyPassReverse /blog http://internalserver/blog
# use to disable access to a specific subdir
Deny from all
Allow from 192.168.1.2
# use to force errors by the internal host to look like to be coming from the proxy host.
# disabled because it causes problems with WordPress.
This is the entire config for the proxy part. Next, enable mod_security. As far as i can see there is nothing special about ModSecurity and reverse proxies. So just enable it like you would on a webserver.
Some useful links for setting up reverse proxies using Apache:
Thats all for now!
I have been using ModSecurity for quite some time now to protect a webserver, but i never felt the need to write my own rules. Recently though, my site got quite a lot of spam in the comments of my TikiWiki based site. Since i was not willing to disable the anonymous comment posting i decided to see if i could use Mod_Security to block the spam.
The spam all looked alike with the following characteristics. It all contained a list uri’s with a pipe | before them. So decided to try the most easy way, by blocking all posts with this characteristic.
SecFilterSelective REQUEST_URI “.php” chain
SecFilterSelective POST_PAYLOAD ” | http:”
And it works fine:
[Sat Jul 01 12:37:32 2006] [error] [client 220.127.116.11] mod_security: Access denied with code 404. Pattern match ” \\| http\\:” at POST_PAYLOAD …
Surely the rule can be much refined, but as long as it works as it does, and i see no bad side effects, i’m happy 😉
I just finished Preventing Webattacks with Apache by Ryan C. Barnett. Even though the title says it is about Apache it is really mostly about Mod_Security, and this is why i really love the book.
Especially cool is the part of the book where the author challenges the user to setup his ‘Buggy Bank’ example application to play with the vulnarebilities and with the possible counter measures.
This book got me even more exited about Mod_Security, which I use already to protect one webserver. I plan to check out setting up a reverse filtering web proxy soon.