Example of Security for htaccess and wp-config.php with exceptions

Blocking Access to the Most Important WordPress Files, including .htaccess, wp-config.php

There are several files that are part of every web site hosting account, that must be kept secret for security. Hackers are very interested in these files, as they contain key information about your hosting account and WordPress database.

This is good to understand, and Everything here is covered by WordFence with less effort for You. Install WordFence on every WordPress site. I wrote this before I found out about WordFence.

403SecretFile:wp-config.phpcomputerhelp.glerner.com/wp-config.php195.154.243.59Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36Accept: */*
403SecretFile:wp-config.phpcomputerhelp.glerner.com/wp-config.php.bak195.154.243.59Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36Accept: */*
403SecretFile:htaccesswebsite-tech.glerner.com/2013-testing-htaccess-lines-without-crashing-your-site68.180.230.49Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)Accept: */* Accept-Encoding: gzip

My error pages log the errors that are detected, into a database. This lets me easily search for errors, and also easily troubleshoot when a valid file triggers an error. These three examples were in my database coincidentally almost the same time, from someone (IP address trying to get information about my site, and someone trying to read an article I wrote but my security system was blocking.

How to Block Files

This is in my .htaccess file:

# prevent access to PHP error logs, other secret files
# need to escape periods (or behaves as "any character"), don't need to escape underscores
SetEnvIf Request_URI (?i).*(htaccess|php\.ini|wp-config\.php|wp-config\.bak|wp-configbak1\.php|debug_log|error_log|404\.log|ignore404\.log|error_log403|error_logbot|500\.log|readme\.html|readme\.txt) badSecretFile=$1

# use syntax like this to enable any special case URLs, the exclamation point un-sets the environment variable
SetEnvIf Request_URI (?i)(/2013-testing-htaccess-lines-without-crashing-your-site) !badSecretFile
SetEnvIf Request_URI (?i)(/2013-xampp-limit-not-allowed-in-htaccess) !badSecretFile
SetEnvIf Request_URI (?i)(/2013-error-reporting-from-htaccess) !badSecretFile
SetEnvIf Request_URI (?i)(/2016-blocking-access-to-htaccess-wp-config-php-other-important-files) !badSecretFile
SetEnvIf Request_URI (?i)(/files/2016/11/security-htaccess-wp-config.php-with-exceptions.*png) !badSecretFile
SetEnvIf Request_URI (?i)(/tag/htaccess) !badSecretFile

# deny doesn't transfer environment variables, except Deny from env= and should be inside a  or  to work
RewriteCond %{ENV:badSecretFile} >"" [NC]
RewriteRule (.*) - [F,L]

Lines 1 and 2 are comments (start with a #)

Line 3 uses a | to separate options. Set an Environment Variable if one of these things matches. Request_URI (the page being requested, so in http://www.yourdomain.com/abcdefg.html, the Request_URI is “abcdefg.html”) is checked for a match. Then (?i) says to ignore upper/lower case. Ignore anything before what we’re interested in, using .* (period for “any character”, asterisk for “zero or more times”). Then a list of file names to check for, e.g. htaccess or wp-config.php. Then we set an environment variable (badSecretFile) to $1 which is the first “something in parenthesis” that was matched. End result, badSecretFile gets set to “htaccess” or “wp-config.php” or “error_log”, etc.

Line 5 through 11 “un-set” the environment variable badSecretFile for some of my pages. I’m writing about techniques on .htaccess, so I have to un-block my pages from the security rules saying nobody gets to read any file with “htaccess” in the name. (When writing security rules like this, be very specific, use the full name of your WordPress page.)

Line 10 has something specific to WordPress. Images are often resized by WordPress to match the sizes your theme wants; the size is added in the file name. http://website-tech.glerner.com/files/2016/11/security-htaccess-wp-config.php-with-exceptions-1080×425.png is the actual file name used in this case, so have to tell .htaccess to allow (with .* ) any extra characters in that location.

Line 13 is a comment about the normal way of blocking access to files, using for example <Files> or similar statements. However, that method doesn’t allow exceptions (would block my articles on how to use .htaccess, for example) and doesn’t provide a way for error pages to report on what triggered the request getting blocked.

Line 14 says that if the environment variable badSecretFile has been set, then the RewriteRule in line 15 gets executed. Line 15 says any file name (.*) gets redirected to – which is the shorthand for “nowhere”, and then the [F,L] says Fail (with a 403 status code, triggering your error page) and this is the Last thing to do (stop executing .htaccess now).

How to Track .htaccess Errors

This is a very long topic, so for now I’ll just say that PHP can read the environment variables that exist in .htaccess.

Here is the snippet of PHP code I use for detecting this particular error, where I used badSecretFile to store what was blocked.

if (!empty($_SERVER['REDIRECT_badSecretFile'])) {
	$htaccessErrors[] = 'SecretFile:'.$_SERVER['REDIRECT_badSecretFile'];

PHP gets the environment values from the requested page in (for example) REDIRECT_badSecretFile, and the values for the error page do not have the “REDIRECT_” prefix. You also have to check for errors that get re-triggered by subdomains, and have REDIRECT_REDIRECT_ prefixes. All of the $_SERVER variables are available to PHP. For example if (!empty($_SERVER['REMOTE_HOST'])) { /* do something */ }

Why Was My Page Blocked?

Simple. I had been blocking page names with a trailing slash, and this person didn’t have the trailing slash in their request (http://website-tech.glerner.com/2013-testing-htaccess-lines-without-crashing-your-site and I only enabled http://website-tech.glerner.com/2013-testing-htaccess-lines-without-crashing-your-site/ )

If I had not been logging my site errors, and checking my log, I probably wouldn’t have found this mistake.

My logging to a database, including having the server tell me what made this be blocked (in this example, “SecretFile:htaccess”) had me see the error and be able to fix it.

If I had not logged what triggered the error, even if my eyes had gone over the log entry, I would not have seen it; I would have thought it was blocked by User Agent (what type of browser was used), or by IP address, or “something”.



Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.