Today I had time for another shot at my new .htaccess, and I can tell you that it got better. I think it's pretty much done now, and I am really happy with it. I also got a couple of questions about how it exactly works. So I post my latest .htaccess here, plus a walkthrough on the various mod_rewrite rules I use. First off, here is my latest beauty: Code: RewriteEngine On Options +FollowSymLinks ServerSignature Off RewriteCond %{REQUEST_METHOD} ^(HEAD|TRACE|DELETE|TRACK) [NC,OR] RewriteCond %{THE_REQUEST} ^.*(\\r|\\n|%0A|%0D).* [NC,OR] RewriteCond %{HTTP_REFERER} ^(.*)(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR] RewriteCond %{HTTP_COOKIE} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR] RewriteCond %{REQUEST_URI} ^/(,|;|:|<|>|">|"<|/|\\\.\.\\).{0,9999}.* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^$ [OR] RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|scan).* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|cast|set|declare|drop|update|md5|benchmark).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(localhost|loopback|127\.0\.0\.1).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*\.[A-Za-z0-9].* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC] RewriteRule ^(.*)$ access_log.php First we set the basic configuration in order to utilize the Apache mod_rewrite module. Code: RewriteEngine On Options +FollowSymLinks Then our first basic rule is to turn off the server signature, which can be helpful in order to stop banner grabbing: I use 2 different flags, namely: Code: NC - Not Case sensitive OR - Or the next rule The first rule is based upon the REQUEST_METHOD. The request method is the method on which a client wishes to connect to our server. I only want GET or POST requests, so I limit methods which I think should not request my server at all. TRACE and TRACK should be blocked in any case, because of the violation of the browsers same origin policy rules. DELETE is optional, but since I won't use it I block it anyway. I also block HEAD request methods, a HEAD request is usually made by law abiding scanners that usually perform banner grabbing and do not want to fetch the whole page. While that might sound reasonable to allow, I block it. Code: RewriteCond %{REQUEST_METHOD} ^(HEAD|TRACE|DELETE|TRACK) [NC,OR] THE_REQUEST is the full request that is being made by a client and consist of a long string. This is usefull to sanitize, because I do not want a client sending me dual headers, or dual requests that can lead to http response splitting, or CRLF injection as it was called in the old days. Code: RewriteCond %{THE_REQUEST} ^.*(\\r|\\n|%0A|%0D).* [NC,OR] HTTP_REFERER can contain characters that could be used to pentest a webapplication, or it can carry a worm payload vector. Blocking characters that will likely never happen in a legitimate request, we make sure that it cannot do something malicious. Code: RewriteCond %{HTTP_REFERER} ^(.*)(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR] The HTTP_COOKIE is equal important, and often a place to store pentest characters or payload. Code: RewriteCond %{HTTP_COOKIE} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR] The REQUEST_URI is important in server protection. Mostly overflow protection, or canonicalization issues like happened with Apache Tomcat for example. With a max of 9999 duplicate characters. Please notice that the REQUEST_URI always contains unencoded (verbatim) characters. Code: RewriteCond %{REQUEST_URI} ^/(,|;|:|<|>|">|"<|/|\\\.\.\\).{0,9999}.* [NC,OR] This rule set checks the USER_AGENT. Of course, it can be forged. But that is not the point. Wget and cURL are somewhat harder to forge on a platform, and many penetration software packages have a hard coded user-agent which sometimes cannot be changed, when it is proprietary software for example. This is only to thwart the less experienced hackers and massive generic bots, which will also save us bandwidth and log annoyances! The first rule checks for an empty user-agent. The lynx browser -for crontabs for example- is allowed because it has libwww-FM as a user agent, whereas I block the libwww-perl user-agent, since scripts can use the Perl libraries to attack. Code: RewriteCond %{HTTP_USER_AGENT} ^$ [OR] RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|scan).* [NC,OR] RewriteCond %{HTTP_USER_AGENT} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR] The QUERY_STRING is probably the most important of all, because that is where most of the actual action is happening. In the rules below I check for a common SQL injection pattern, pentest characters for XSS, and also for remote shell injection in the 3rd rule because periods should actually not be present in the QueryString in my opinion. Code: RewriteCond %{QUERY_STRING} ^.*(;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|cast|set|declare|drop|update|md5|benchmark).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(localhost|loopback|127\.0\.0\.1).* [NC,OR] RewriteCond %{QUERY_STRING} ^.*\.[A-Za-z0-9].* [NC,OR] RewriteCond %{QUERY_STRING} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC] Finally, we rewrite the request to a fail-safe page. This can be a script that logs all the information -which I do not recommend- If possible send it to a forbidden page. Anything you wish. Code: RewriteRule ^(.*)$ access_log.php (c) Ronald Aurea van den Heetkamp aka rvdh http://rvdh.ath.cx/index.php?i=268