Use .htaccess to whitelist two files for execution - apache

I have a website that has a folder for images.
I have two problems:
I want to disable all script execution in that directory (i.e. no PHP/Perl/Python
anything.)
There are two php files in my images folder called gradient.php and rgba.php – I do what those to run as per usual.
How do I set up my .htaccess file to do that. Also, rather than placing a new .htaccess in the images directory, is it possible to incorporate these directives in the one in the site root?

You can add these rules to the htaccess file in your site root:
# check if the request is for the images folder
RewriteCond %{REQUEST_URI} ^/images/
# check that it isn't a request for an image
RewriteCond %{REQUEST_URI} !\.(jpe?g|png|gif|bmp)$ [NC]
# check that it isn't a request for the 2 ok php files
RewriteCond %{REQUEST_URI} !^/images/(gradient|rgba)\.php$
# forbid access
RewriteRule ^ - [L,F]
This should make it so any request for /images/ that doesn't end with jpg/jpeg/png/gif/bmp (or whatever other extension you want to add to the regular expression) or isn't gradient.php or rgba.php, will result in a 403 forbidden.
EDIT:
I don't want them to be forbidden, I just want them to not execute – it's an upload folder, so I basically want it that if someone uploads a JPG that is secretly PHP code that I haven't detected, that it won't run
as long as jpg and other images are mapped to the correct mime/type (via AddType image/jpeg .jpg) then it won't get handed to the php handler and whatever code is there won't get executed. If you want to serve all files using the default handler, you need to set AddHandler default-handler php in the htaccess file in your images directory. You'll then need to move the gradient and rgba files out to some other directory. You can't selectively set handlers from an htaccess file, though you may be able to use <Location> blocks to set handlers in your vhost config.
EDIT 2:
I was wrong, you can use the H flag to set a custom handler using a rule. So in the above rules, instead of [L,F], you can do [L,H=default-handler] so that anything that isn't an image or gradient.php or rgba.php will get sent to the default-handler (e.g. php files will get sent as-is, and not handled and executed by mod_php).
So you can just do:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/images/(gradient|rgba)\.php$
RewriteRule ^ - [L,H=default-handler]

Related

How to prevent user to access images in multiple directories via the url

I am using .htaccess to prevent user to access images through url.
Thanks to this question, I could prevent users to access .js files.
RewriteEngine ON
RewriteRule ^frontend/assets/(?:js) - [R=401,NC,L]
However, when I applied the same rules in order to denied access to dir1 and dir2, the access is only denied to images in directory dir1.
RewriteRule ^frontend/assets/images/(?:dir1|dir2) - [R=401,NC,L]
Is there a way to handle this and prevent users to access files in directory dir2 as well ?
Please try following htaccess rules file. Apart from fixing regex we need to be careful on where we need to place the rule. So place this rule before your previously used rule(s).
Please make sure to clear your browser cache before testing your URLs.
##Enabling RewriteEngine here...
RewriteEngine On
##Rewrite rule for images with checking users OR uploads here...
RewriteRule ^free/frontend/assets/images/(?:users|uploads) - [R=401,NC,L]
##Rewrite rule for images OR css OR js folders here....
RewriteRule ^frontend/assets/(?:images|css|js) - [R=401,NC,L]

Can htaccess "try" different extensions?

I have a folder with images uploaded by users in a few different formats. The files get numbered by my upload script with a unique ID.
When displaying them via php, I want to be able to link to them without knowing (or having to save in the database) their extension (i.e. images/42, images/69 and not images/42.png, images/69.jpeg. I have been doing some research but can't really come up with a way to write my .htaccess correctly. What I've done so far doesn't work and I had no success either trying to come up with my rewrite conditions. Any suggestions?
RewriteRule ^(.*)/?$ $1.(png|jpg|jpeg|gif) [QSA,L]
I've found this but can't really adapt to my problem: https://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_s
Yes, you can manually try each extension in turn. Each extension will require a different rule. The first extension that matches will "win". If an extension matches then force the respective mime-type.
I assume your image URLs are of the form /images/<number>. This needs to be specific otherwise we will unnecessarily test the wrong URLs.
For example, near the top of your root .htaccess file:
# Check for ".webp" file (and check browser support)
# NB: If webp not supported then there needs to be a fallback (.png or .jpg)
RewriteCond %{HTTP_ACCEPT} (?:^|,)image/webp(?:,|$)
RewriteCond %{DOCUMENT_ROOT}/$0.webp -f
RewriteRule ^images/\d+$ $0.webp [T=image/webp,L]
# Check for ".png" file
RewriteCond %{DOCUMENT_ROOT}/$0.png -f
RewriteRule ^images/\d+$ $0.png [T=image/png,L]
# Check for ".jpg" file
RewriteCond %{DOCUMENT_ROOT}/$0.jpg -f
RewriteRule ^images/\d+$ $0.jpg [T=image/jpeg,L]
# Check for ".jpeg" file
RewriteCond %{DOCUMENT_ROOT}/$0.jpeg -f
RewriteRule ^images/\d+$ $0.jpeg [T=image/jpeg,L]
# Check for ".gif" file
RewriteCond %{DOCUMENT_ROOT}/$0.gif -f
RewriteRule ^images/\d+$ $0.gif [T=image/gif,L]
The $0 backreference contains the entire URL-path that is matched, eg. image/42. Each RewriteCond directive checks for the existence of the file with the respective file extension before internally rewriting the request to that file. The T flag ensures the correct Content-Type header is sent with the response.
images uploaded by users in a few different formats.
An alternative approach is to convert the image into a specific format as part of the upload process. So you always rewrite to .png (for example) - which will be more performant. And this has the added "security" benefit that malicious files (scripts that are "pretending" to be images) will get rejected since the image conversion will likely fail.
MultiViews (alternative)
Alternatively, you could simply enable MultiViews and let mod_negotiation do the work. mod_negotiation then checks various file extensions that return the appropriate mime-type and will return a resource that matches.
For example:
Options +MultiViews
No mod_rewrite directives are necessary.
HOWEVER, you don't have as much control over this, unless you manually create a type map in the server config and this might conflict and cause problems if you have other mod_rewrite directives. MultiViews will apply to everything unless you restrict it to certain paths.
RewriteRule ^(.*)/?$ $1.(png|jpg|jpeg|gif) [QSA,L]
You can't do it in a single rule like this. This directive also matches everything (ie. ^(.*)/?$) - which naturally includes every URL that does not map to an image. The substitution string is an ordinary string, not a regex, so a construct like (png|jpg|jpeg|gif) is seen as literal text. The QSA flag is irrelevant here. The query string is appended by default anyway, but do you image URLs have a query string to begin with?

.htaccess Redirect Media File Requests to a Different Domain/Server

Simply speaking, I want to substitute one file path for another in the URI, but only for certain file types.
I have a load of image files (PNG, GIF and JPG) on one server and a wordpress installation on another server. I can't put them all on the same server at the moment (for reasons too complicated to go into).
So, when I get a request for a PNG, GIF or JPG file on e.g.
http://www.server1.com/images1/image1.png
I want to be able to divert this request to the same image, but on server 2, potentially in a different top level subfolder e.g. "allimages" such as:
http://www.server2.com/allimages/images1/image1.png
Then, say divert:
http://www.server1.com/images2/image2.png
to
http://www.server2.com/allimages/images2/image2.png
I tried to make a start with .htaccess (on SERVER1) but haven't got very far. I put a .htaccess file in the root of Server 1, with these lines in:
RewriteEngine On
RewriteCond %{REQUEST_URI} (\.png|\.jpg|\.gif|)$
RewriteRule ^(.*)$ http://www.server2.com/allimages/$1 [L,R=301]
But I know this isn't correct. Can anyone help? Many thanks!
Try with:
RewriteEngine On
RewriteRule ^(.+(?:\.png|\.jpg|\.gif))$ http://www.server2.com/allimages/$1 [L,R=301]

mod_rewrite inserting full path to file

I need to create a rewrite to take traffic going to mp3/mp4 files in a specific subdirectory and then route them to a PHP file that tracks download stats etc before routing them to the actual file location since iTunes requires your podcast RSS contain actual media file extensions (.mp3, .mp4, etc)
I have created rewrites before with no problem but now I am running into an odd issue on this company's server.
My .htaccess located at www.company.com/companytools/podcasts
RewriteEngine on
RewriteRule ^/(.*).mp3$ /test.php?file=$1 [r=301,L]
Right now it is partially working it does act upon the mp3 file but ends up including the full path to test.php after the domain, so I end up with a 404 page looking for this URL:
www.company.com/www/internal/docs/companytools/podcasts/test.php?file=test
basically I need the path, but only the /companytools/podcasts part.
Any help is appreciated.
You may not need R=301 here to hide actual PHP handler.
Try this rule with RewriteBase:
RewriteEngine on
RewriteBase /companytools/podcasts/
RewriteRule ^(.+?)\.mp3$ test.php?file=$1 [L,QSA]

Excluding one directory in .htaccess (not just rewrite rules)

Excluding one or more directories from rewrite rules in .htaccess files seems to be a common question. However, my .htaccess does more than just set rewrite rules. I've also set some server changes (we don't have suPHP on this server) as well as set some prepending of some php files. For example these are a few examples:
# Make files ending in .php, .html and .xml files etc. parsed by php.
AddType application/x-httpd-php .php .html .xml .css .js .le .txt
<FilesMatch "\.html$">
php_value auto_prepend_file "/home/2427/spwebsites/www.spwebsites.co.uk/incs/phps/config.php"
</FilesMatch>
# Internal Server Error
ErrorDocument 500 /admin/errors.html?code=500
RewriteEngine On
RewriteRule ^([a-zA-Z0-9-]+)/$ $1.html [L]
I don't want any of these set for one directory (where my word press installation is), is there a way I can do this? Can I set a conditional statement for the whole .htaccess file?
Adding a blank .htaccess file in the word press directory won't work because this won't undo the settings in the parent directory.
I was just looking into your dilemma and it is a tricky one. It would be nice to be able to have the DirectoryMatch directive available in .htaccess ...
What you can try is to reset your values in the specific directory via another .htaccess file.
So in the case of the AddType perhaps, resetting it back to just ".php" might work (assuming it doesn't inherit the other values). Definitely not an ideal solution with out access to the main config file/ virtual host.
Here is a weird idea that you can try/test ... place the "wordpress" dir outside of the main root (or whereever you have the offending .htaccess file). Now route all requests to the wordpress (inner dir) to the outer dir. I wonder if Apache would not use the offending .htaccess considering the requests are being routed?