Protect images through .htaccess and PHP - php

I would like to check if users are logged in to access image files.
Images would have this form
https://domain.com/folders/imagename.jpg
I tried this in the .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_URI}\.jpg
RewriteRule ^(.*)\.jpg$ /protect.php
And this in my protect.php file
<?php
if(rcp_is_active()){
header('Content-Type: image/jpg');
readfile($imageurl);
}
else{
readfile("https://placeholdit.imgix.net/~text?txtsize=38&txt=Forbidden&w=400&h=400")
}
?>
My question:
How should I complete my .htaccess file to pass the filename.jpg to the php file?

Update your .htaccess RewriteRule to pass the matched filename to the PHP script as follows (your RewriteCondition is superfluous):
RewriteEngine On
RewriteRule ^((.*)\.jpg)$ /protect.php/$1
Then you can access the passes value using $_SERVER['PATH_INFO'] or $_SERVER['PATH_TRANSLATED'] (then Apache tries to map it to the real path according to document root, see mod_cgi and RFC 3875 for more information about this). For this to work AcceptPathInfo needs to be enabled in Apache httpd (the default).
or use
RewriteRule ^((.*)\.jpg)$ /protect.php?filename=$1
and use $_GET['filename']. Especially here, beware for directory traversal attacks (e.g., someone uses /protect.php?filename=../../someother-file.jpg). I usually apply realpath to normalize the path and check that it starts with the folder which contains the files or the document root ($_SERVER['DOCUMENT_ROOT']).
In both cases also make sure you only deliver allowed files (e.g., what happens if an attacker uses /protect.php/protect.php). This might leak sensitive data.
PS: Maybe you also want to make the response non-cacheable or provide a Content-Length.
PSS: Even for the forbidden case you also need to provide a proper Content-Type - or use a redirect (header('Status: 302'); and header("Location: https://placeholdit.imgix.net/~text?txtsize=38&txt=Forbidden&w=400&h=400");) so that you don't need to re-request that image again and again.

Related

How I can redirect when request to download a file in Apache http server

I want to redirect to another url when request come to apache http for download a file
for example, client call https://example.com/download/apps/v1.01.apk
/download/apps/v1.01.apk is a real path
I want when call url apache prevent to download it and redirect to another url
For this, you will need to use a .htaccess file.
Create a .htaccess file, in the root of your project and type this into the file:
RewriteEngine on
Options -Indexes -Multiviews
RewriteRule ^(v1\.01\.apk)$ your-new-url.php
It's worth keeping in mind that when the web server first receives a request, the URL is just a string, and the server has to decide what to do.
One of the things it can do is look for a file on disk whose name matches the URL. If it finds a file, it can decide what to do with that information, perhaps combined with other information the browser sent in the request, or information it finds about the file.
Eventually, the server will come up with a response - maybe a response with the content of the file it found; maybe the result of running a particular script; maybe a response indicating a redirect to a different URL.
With most web server software, you can configure all of these decisions, in very flexible ways. So you can say "if the URL has a v in it, look for a file in this folder; if it exists, run this PHP script with the file name as an argument; if it doesn't, issue a redirect response to a URL where the v is replaced with an x".
For Apache, you will see a lot of advice to use .htaccess files to do this. These are not the primary configuration for Apache, but they are a convenient place to put extra configuration when you are using a shared server and can't edit the main configuration for security reasons.
The specific configuration line used to trigger a redirect response in Apache looks like this:
RewriteRule pattern-to-match-against-request url-to-redirect-to [R]
The first argument is a "regular expression" which can be as general or specific as you want. Note that . means "any character", so if you want to match a dot specifically, write \.
The second argument can contain variables like $1 and $2 which refer to parts of the requested URL "captured" by putting them in brackets in the pattern.
The [R] at the end can also have a type, like [R=temp] or [R=307], which will change how the browser handles the redirect, caches it, and so on. There are also other flags your can add, like [R,NC] for "Redirect, Not Case-sensitive".
Finally, you can add any number of RewriteCond lines before a rule, such as RewriteCond -f %{REQUEST_URI} meaning "if a file exists with the same name as the requested URL.

Run PHP script when file from a certain directory are requested

I have just written some PHP code to combine all the JS on my website into a single file, hash it, then echo out the <script> tag with the hashed filename as the source. I store all these hashed files in a single folder, and delete old hashes every time a new hash is generated.
I want to be able to turn on caching for this file, as the hashed filename determines when the browser needs to download a new file (IE: The actual URL that it requests is different). Does anyone know how to hook into this request in PHP? Something like:
if ($_GET['folder'] = "path/to/hashed/folder/or/file")
{
//Do something
}
Any help is greatly appreciated.
Unless you are serving your JavaScript with PHP, you can't hook into the request. However, you don't need to set caching headers with PHP. You can configure your web server to do this directly. How you do this depends on what server you are using.
What you are going to use for this is a file called .htaccess. Here is a simple rule that sends everything through one file, here named index.php.
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !^/some_file_that_you_want_to_exclude_from_this_rule
RewriteCond %{REQUEST_URI} !^/some_other_file_that_you_want_to_exclude_from_this_rule
RewriteRule ^(.*)$ index.php [L]
The full URL will be in $_SERVER['REQUEST_URI'], and other variables in $_SERVER will point you to other information ($_SERVER['REDIRECT_URL'] excludes the host name).

RewriteRule based on file existence with another name

We currently use an image resizer that was written in PHP. The resizing script takes advantage of caching, and writes the generated resized images to a cache directory (aptly named cache/).
The process is such that a rewritten URL, for example:
domain.com/img/250x250/some-image.jpg
Will be re-written to:
domain.com/image.php?width=250&height=250&src=some-image.jpg&function=resizeCrop
Inside image.php, we make a check to see whether a file matches the resize in the cache/ dir. All cached images are stored with a name of cachFunctionWidth_height_originalName, so for the given example the generated image file inside cache/ would be named resizecrop250_250_some-image.jpg
At the moment, we're utilizing PHP's fpassthru() function to output the file to the browser if it exists. If it doesn't we use a combination of GD functions and algorithms to output the file to the browser.
My question is whether it will be possible for us to bypass the image.php completely if a resized image exists in the cache directory using HTACCESS (it's a Linux server). Essentially, we need to check for a bastardized name form before serving rewriting.
For example, here's some pseudo-code of what we'd like to achieve, but I don't think it's possible:
User requests file > domain.com/img/250x250/some-image.jpg
Check if file cache/resizecrop250_250_some-image.jpg exists
If it does, rewrite to cache/resizecrop250_250_some-image.jpg
If it doesn't, rewrite to domain.com/image.php?width=250&height=250&src=some-image.jpg&function=resizeCrop
If this is not possible through HTACCESS, any other suggestions would also be welcome.
I believe using mod_rewrite it is possible. Consider following rule:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# check if constructed image name exists in cache directory
RewriteCond %{DOCUMENT_ROOT}/cache/resizecrop$1_$2_$3 -f
# exists, redirect to cache/constructed-image-file-name
RewriteRule ^img/([0-9]+)x([0-9]+)/([^.]+\.(?:jpe?g|gif|bmp|png))$ /cache/resizecrop$1_$2_$3 [L,NC]
# doesn't exist then forward to image.php with required query parameters
RewriteRule ^img/([0-9]+)x([0-9]+)/([^.]+\.(?:jpe?g|gif|bmp|png))$ /image.php?width=$1&height=$2&src=$3&function=resizeCrop [L,NC]

Is it possible to set an environment variable in PHP and redirect via .htaccess based on that environment variable?

I have a protected folder. I want people who are logged in (via PHP / WordPress) to have access to the folder and the files therein.
Those who are not logged in should be redirected via .htaccess.
Can the .htaccess rewrite condition be based off an environment variable or a server variable which I added or edited from PHP?
UPDATE:
See my answer below.
.htaccess (hypertext access) file is a directory-level configuration file supported by several web servers. I can't think of any simple way of how you could access runtime variables set in PHP with .htaccess as .htaccess allows no "execution" of commands, it is just a bunch of config directives.
You could maybe do some sort of VERY VERY strange combination of .htaccess and CGI scripts and maybe more to access a webservice # PHP level, but that would be far beyond my programming skills and I suppose beyond those of most PHP developers too...
At least this is what I can tell you, I would be interestd too if someone knows a hack for this...
The easiest way of how to do such redirects would in my opinion be header("Location: xxx.html"); directly in PHP.
You can't edit the .htaccess file on the fly using PHP to set these variables. I mean, you can, but the .htaccess file is used by the entire server, not per-user. Unless you wanted to do some ridiculous write-username-environment-variables to .htaccess and hope it works somehow, you're much better off just doing this via php. If they're not logged in, you can redirect them away with PHP so they won't be able to see the protected folders either.
If you want to keep them out of an entire folder but you don't want to do something like require security-check.php on every file, you could look into using auto_prepend_file. You could also use your .htaccess to route all file access through one specific php file that does this. You would need to do this if you were keeping people out of non-php files.
After much research, I solved it.
My folder system is setup like this:
/file-share/users-folder-name
My .htaccess file under /file-share is as follows:
# .htaccess /file-share
RewriteEngine On
RewriteBase /
# no cookie set
RewriteCond %{HTTP_COOKIE} !^.*client.*$ [NC]
RewriteRule ^(.*)$ /file-share-redirect.php?q=$1 [NC,L]
# cookie set
RewriteCond %{QUERY_STRING} !verified$ [NC]
RewriteCond %{HTTP_COOKIE} client=([^;]+) [NC]
RewriteRule ^(.*)$ /file-share/%1/$1?verified [NC,L,QSA]
# custom 404
ErrorDocument 404 /file-share-redirect.php?e=404&q=$1
#end
If the cookie is set and the file exists in the client's folder then the client is redirected seamlessly to the requested file. The final file request is also given a url parameter to avoid a loop in redirection.
If a user is logged but the cookie is not set I have my file-share-redirect.php file create the cookie then redirect to the requested file. The cookie created in the code below is set to expire in an hour.
<?php setcookie('client', $users_folder_name, time()+3600); ?>
UPDATE
You can keep the cookie secure by using an encrypted cookie name and value. The cookie will only be created on systems where users log in.
PHP's setcookie() will even let you create a cookie that is inaccessible from JavaScript. I double checked this.
The subfolder names will be quite complex, completely unguessable. No one will ever see the subfolder names except those with ftp access. Even those logged in will only see /_/filename.ext, without the subfolder.

Best strategy to protect downloadable files -php/mysql Apache2 server

I'll trying to figure out how to protect directory from unauthorized or not autentificated user to download files.
Thank's in advance.
Can't find a good duplicate, but a little search will bring up results like this PHP protect a folder
There is a simple way to restrict folder access based on PHP session authorization using php. It requires creating stub files for valid authorized sesssions (and automating their deletion). In PHP you do:
if ($user_has_permission_to_download)
{
touch("tmp/access-" . session_id());
}
Then a simple rewriterule+rewritecond can then serve for authorization:
RewriteCond %{HTTP_COOKIE} PHPSESSID=(\w+)
RewriteCond ../tmp/access-%1 -f
RewriteRule ^(.+)$ $1 [L]
RewriteRule .+ /deny [L]
The first block permits access when the according cookie value is found and an authorization stub file exists. The second rule blocks access for anyone else.
Put a .htaccess file in the directory with the files, with the following content
deny from all
Then create a script that that uses for instance readfile() to serve the file if the user is authorized.
I'm assuming you have a users / login script somewhere that authenticates a user?
Use .htaccess rewrite rules to forward the file request through a php script that checks a session variable if the user is logged in then returns the file.
Something of the elk:
.htaccess
RewriteEngine on
RewriteRule ^(.*).(pdf|exe|doc|whatever)$ some-script.php?file=$1.$2 [L]
<?php
if(loginCheck()) //function somewhere that checks session if user is logged in
{
return fopen('../files/' . $_GET['file']); //open and return the requested file
}
This is just pseudo code to give you an idea of what you need to do. You may also have to echo the correct file headers as well.
And to stop people from just going to the files directory, I recommend putting an .htaccess file in THAT folder as well saying deny from all to stop EVERYONE from accessing it.
.htaccess is your best friend. Put deny from all into that .htaccess file. Or if you don't want to use .htaccess file encrypt and change all the time the download path (LOL!).

Categories