Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Apache forbid a file only if it exists?

I've been working on this problem for a couple hours no, still with no resolution. In case you don't understand what I'm asking from the title, I'll elaborate. I'm trying to forbid access to certain stylesheets and scripts from Apache, but I only want it to throw the 403 error if the file doesn't exist.

Here's some examples of what I have tried:

RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule (admin|staff)-?[a-zA-Z1-9]*\.(css|js|php)(.map)?$ - [F,L,NC]

This didn't work for some strange reason, have no idea why.

Also, before I continue on with more examples, I'll explain what I'm trying to achieve with the regex: I'm using versioning, so I can never be sure what comes after the admin and staff, so I'm using a optional character class. It only affects css, js and php extensions, as well as css.map extensions. By the way if your wondering why there is a dash in between the character class and the admin|staff part of the regex it's because my versioning tool seperates the date and the file name with a dash. Just in case this infomation will help you the versioning tool I am using is Laravel Elixir.

More Examples:

RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME} -f
RewriteRedirect 403 (admin|staff)-?[a-zA-Z1-9]*\.(css|js|php)(.map)?$

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRedirect 404 (admin|staff)-?[a-zA-Z1-9]*\.(css|js|php)(.map)?$

In this example whatever one you put first it call that error code.

I've even tried using the directive but it seems to be called even if the file doesn't exist.

<FilesMatch "(admin|staff)-?[a-zA-Z1-9]*\.(css|js|php)(.map)?$">
    deny from all
</FilesMatch>

Thanks for any help you can provide, for some reason I can't seem to find anything on this sort of thing online!

Edit:

Covenor wanted some examples so here they are:

  • /anydirectory/admin-12d16m4.css

  • /anydirectory/staff.js

  • anydirectory/admin.php

Edit 2:

Thanks to Covenor, I've partially fixed my problem. Here's my code now:

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule (admin|staff)-?[a-zA-Z1-9]*\.(css|js|php)(.map)?$ - [F,L,NC]

This works, for files like admin.css, admin.js, admin.css.map, but as soon as I implement the versioned files it doesn't hide them. Here's an example of a versioned file name: app-968b520079.css . It isn't hiding it even though I can't find a problem in my regex.

Thanks for any more help.

Final:

Thanks to everyone that has helped, the issue has been fully resolved. For anyone who wants to know the exact code I used, here it is:

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule (admin|staff)-?[A-Za-z0-9]*(.min)?(?(-1)(css|js)|(css.map|css|js|php))$ - [F,L,NC]

P.S, I'm not sure who to give the bounty to, so whoever gets the most votes will get the bounty.

like image 404
Dastur Avatar asked Aug 12 '16 03:08

Dastur


2 Answers

There are two reasons why it's not matching app-968b520079.css

The first is the "app" bit, which is not contained in the

(admin|staff)

at the beginning of your regex.

You should change that to

(admin|staff|app)

if you want to match anything starting with "app-".

The second is the fact that the 968b520079 contains two zeros, and you're testing for

[a-zA-Z1-9]

which means: a to z, A to Z and 1 to 9

You should test for 0 to 9, change it to

[a-zA-Z0-9]

and your regex shoud work just fine.

like image 154
Paolo Mioni Avatar answered Nov 07 '22 16:11

Paolo Mioni


Your first "what I tried" example only matches when the translated URL is simultaneously a directory and a file, which is never true. You need [OR] to join the two conditions or drop the -d condition completely (due to your regex matching things that would commonly be files not directories)

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule 403 (admin|staff)-?[a-zA-Z1-9]*\.(css|js|php)(.map)?$
like image 37
covener Avatar answered Nov 07 '22 15:11

covener