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

2

7

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.

Debarath answered 12/8, 2016 at 3:4 Comment(7)
What are some example URLs? For all we know your regexes simply don't match.Frederique
RewriteRedirect? Are you transcribing or copy and pasting? I assume it's RewriteRule.Frederique
No rewriteredirect was working it redirects to the apache 403 pageDebarath
RewriteRedirect is not a standard mod_rewrite directive is my point.Frederique
I must have used something else similarily names than...because I was remembering that one from memory. Sorry.Debarath
It's important to copy/paste the rules [and trace] and not paraphrase them.Frederique
I edited, and the directory I meant to write there was redirectmatchDebarath
D
4

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.

Dancer answered 16/8, 2016 at 11:24 Comment(1)
Thanks I completely missed the zero and the app I just forgot to change the name when I copy pasted the example as I currently do not have an admin stylesheet.Debarath
F
2

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)?$
Frederique answered 14/8, 2016 at 12:44 Comment(6)
What I tried was working, except it would still show 403 errors on files that don't exist.Debarath
RewriteLog or Loglevel rewrite:trace8 should clear up any confusion about why some recipe works/doesn't/etc.Frederique
The issue is apache for some reason isn't capable of checking if the file is real, it just throws the 403 if the url matches the regex instead of checking if the file is real.Debarath
Are these in directory/ htaccess context or virtualhost? Only in the former is REQUEST_FILENAME an absolute path. It's a FAQ.Frederique
They are in a .htaccess fileDebarath
In my experience it's never going to be "wrong" about a -f or -d.Frederique

© 2022 - 2024 — McMap. All rights reserved.