Deny Access to All Files Except index.php in htaccess

.htaccessapache-2.2

When I try limiting file access to just index.php using something similar to the answer in the link below I am unable to access through the directory index such as "DIRECTORY/" and "DIRECTORY".

I want to be able to do the below and deny all files except index.php from a .htaccess file in DIRECTORY.

Denying access to all files except index.html apache

DIRECTORY/index.php?get1=val1  
DIRECTORY/?get1=val1  
DIRECTORY?get1=val1

Best Answer

To allow mod_dir to make the internal subrequest for the DirectoryIndex when requesting the bare directory, you just need to make the file match optional, so it also matches an essentially empty filename.

For example:

Order allow,deny
Deny from all
<FilesMatch ^(index\.php)?$>
  Allow from all
</FilesMatch>

This then allows both

  • DIRECTORY/index.php?get1=val1
  • and DIRECTORY/?get1=val1

Where DIRECTORY is any directory (including the document root).

However, this does not permit DIRECTORY?get1=val1 (no slash after the directory name). Strictly speaking, this is an invalid URL on Apache. Ordinarily, mod_dir "fixes" the URL by issuing a 301 redirect to append the trailing slash. ie. DIRECTORY?get1=val1 is externally redirected to DIRECTORY/?get1=val1. Unfortunately, the authorisation directives above block mod_dir from making this redirect.


If you specifically wanted to allow DIRECTORY?get1=val1 (no trailing slash) as well then you could instead do everything with mod_rewrite instead of mod_authz_host (Apache 2.2). For example, replace the above with the following:

RewriteEngine On
RewriteRule ^DIRECTORY/(?!index\.php|$) - [F]

This blocks access to the contents of the specific DIRECTORY, but allows /DIRECTORY/index.php and /DIRECTORY/ to be accessed. This doesn't do anything special with a request for /DIRECTORY (no trailing slash), but executes sufficiently late in the request for mod_dir to step in first and issue the 301 redirect (mentioned above).

(?!index\.php|$) is a negative lookahead - which is successful when index.php or $ (end of URL) does not match. ie. It matches everything except index.php and nothing.


Reference: