2

Can anyone guide me on how I can limit the file types that can be downloaded in Apache from a directory listing?

I have some Directory definitions in httpd.conf, like the following:

<Directory "/var/www/data01">
    Options Indexes FollowSymLinks
    Require all granted
    AllowOverride none
</Directory>

What I want to let the user do is list ALL of the files in every folder but only download files with specific extensions (e.g. *.txt)

I've tried this:

<Directory "/var/www/data01">
    Options Indexes FollowSymLinks
    IndexOptions ShowForbidden
    Require all granted
    AllowOverride all
    order allow,deny
    <FilesMatch "\.txt$">
        order deny,allow
        allow from all
    </FilesMatch> 
</Directory>

But this gives me a 'You do not have permission to access' error when I browse a folder.

0

You could use mod_rewrite. Try the following:

<Directory "/var/www/data01">
    Options Indexes FollowSymLinks
    IndexOptions ShowForbidden
    Require all granted
    AllowOverride all

    RewriteEngine On
    RewriteRule !(\.txt$|^$) - [NS,F]
</Directory>

This prevents access (403 Forbidden) if not requesting a .txt file or the bare directory (required in order to get the directory listing). The NS (nosubreq) flag is required in order to skip internal subrequests. When the directory listing is generated, an internal subrequest appears to be triggered for each file in the directory. So, without the NS flag, the directory listing is ultimately blocked.

Require all granted
order allow,deny

You shouldn't really mix Require (Apache 2.4+) and Order allow,deny (Apache 2.2). The Apache 2.2 directives are only available for backwards compatibility. You should be using Require on Apache 2.4+. Incidentally, these two directives do the opposite... the first one allows access, then the second denies it. The net result is that access is denied (but that's not because of the order of these directives, but because "denying" access wins).

UPDATE: To get this to work on subdirectories as well then change the RewriteRule directive to:

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule !\.txt$ - [NS,F]

The RewriteCond (condition) directive ensures that the following directive only applies to actual files (ignoring directories). This allows us to simplify the RewriteRule pattern slightly since we don't need to explicitly check for the base directory.

2
  • Excellent, thanks for that, and thanks for the info on the 2.4 / 2.2 directives. It's almost working as I need now, except I get a 403 if I try to go to any subfolders. Is there a way to get the rewrite rule to work on any subfolder too? (my regex skills are weak!) – MartinC Mar 30 '17 at 22:50
  • I've updated my answer to allow for subdirectories. You'll need to change the single RewriteRule directive into a RewriteCond + RewriteRule. – MrWhite Mar 30 '17 at 23:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.