I have an ADMIN script.
admin/index.php
All activity is done through this index.php
file.
Users are logging in before gaining access to the program functionality.
$_SESSION['user_authenticated']
is created and set to true.
admin/template/..
This folder contains images
, css
, javascript
files.
They are used only within this ADMIN. (in the backend only)
The question:
I need all the content from admin/template/..
directory to be protected against direct access.
It should be available only to authenticated users.
I guess there has to be a .htaccess
redirecting requests to check_session_auth_variable.php
, which looks if $_SESSION['user_authenticated']
is true or false and redirects to requested file or throws a 404 error?
I know that the best option would be to place the directory outside of the web root, but in my case I need to keep the directory structure as is, without modification.
admin/.htaccess:
RewriteCond %{REQUEST_FILENAME} !check_auth.php
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .* check_auth.php?file=$0 [QSA,L] # pass everything thru php
admin/check_auth.php:
$file = $_GET['file'];
if($_SESSION['user_authenticated']) {
// please mind you need to add extra security checks here (see comments below)
readfile($file); // if it's php include it. you may need to extend this code
}else{
// bad auth error
}
Okay, here is my answer - and it's true that the best answer is 'no'. But the images/js/css are relatively important in development (before becoming public when live) and client previews dictate that we can't do an IP based apache rule. So, the rule (from above, slightly amended) is
RewriteEngine On
# Exclude the public and error directories from authentication
RewriteRule ^(public|error)($|/) - [L]
# Perform authentication via php
RewriteCond %{REQUEST_FILENAME} !auth.php
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .* auth.php?requested_file=$0 [QSA,L]
(because I needed a few subdirectories where content was indeed public, read: the images/css/js used on the login page)
and the relevant php is as follows; for
if($authenticated){
if($extension == 'php'){
call_user_func(function(){
$file_name = func_get_arg(0);
$path = getcwd();
chdir(pathinfo($file_name,PATHINFO_DIRNAME));
return include($file_name);
chdir($path);
}, $file_name);
} else {
//set cache headers so the browsers don't have to refresh all the
// static content
header_remove('X-Powered-By');
header_remove('Transfer-Encoding');
header_remove('Cache-Control');
header_remove('Pragma');
header_remove('Expires');
//header('Expires:');
header('Content-type: '.$mime_type);
readfile($file_name);
}
}
what this does is executes php using call_user_func()
to stop namespace pollution, include()
to execute PHP, and chdir()
to make sure the script gets a proper current working directory.
That's the 'easy' part; the content headers and mime type have to be 'guessed' (I used finfo for the mime types, but it has a bug as at 2013, and this only serves to exacerbate the issue) but even apache can't do that 100% properly...
Then delete the cache control headers for images otherwise you'll not only be often as php pages as well...
suffice to say; you only need to do this if you have thick pipes and a lot of cpu cycles you don't need...
I usually use this
$redi_ext = $_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
$php_verify = strpos($redi_ext, ".php");
if($php_verify !== false){ header('location: PAGE_NOT_FOUND_URL'); }