My PHP app uses 404 Documents to generate HTML files so that multiple queries to the same HTML file only cause the generation to run once.
I'd like to intercept requests to the HTML files so that the user needs to have an established PHP Session in order to pull up the files.
In the best case, SESSION ID would be used in the URL and force it could be used as a further authentication. For example, logging in would issue you a SessionID and make only certain HTML files accessible to you.
I'm aware that by changing my cookies I could spoof a request, but that's fine.
How would I go about doing this?
Something like this could work (I haven't tested it):
RewriteCond %{HTTP_COOKIE} PHPSESSID=([a-zA-Z0-9]+)
RewriteCond %{REQUEST_FILENAME} %{REQUEST_FILENAME}-%1.html
RewriteRule ^ %{REQUEST_FILENAME}-%1.html
It assumes that you append "-$session_id.html" to filenames ($session_id is PHP's session ID).
It should be safe, and the benefit is that files are served by the web server directly without invoking PHP at all.
SetEnvIf HTTP_COOKIE "PHPSESSID" let_me_in
<Directory /www/static/htmls>
Order Deny,Allow
Deny from all
Allow from env=let_me_in
</Directory>
Of course user can manually create such cookie in his browser (there are extensions which do that for Firefox, and you can always edit your browser's cookie store).
You could use the Apache module mod_rewrite to redirect requests of .html URLs to a PHP script:
RewriteEngine on
RewriteRule \.html$ script.php [L]
The requested URI path and query is then available in the $_SERVER['REQUEST_URI'] variable.
Put you cached files out of your web root, but still in a place where PHP can access them.
Related
I am currently running a PHP website, and I was wondering if there is any way to deny access to an image, if the directory was entered in the browser bar, but still be able to use said image in my Page with the <img src=""> tag.
I store said image in a directory called "images" which is on the same level with my main page "home.php". I am familiar with the .htaccess file and the deny from all command in it, however, as I said, it will not display the 'forbidden' files in the other pages. I hope that somebody can help me. Thanks!
Maybe you can try this:
<Files "./your_directory/yourfile.png">
Order Allow,Deny
Deny from all
</Files>
Basically, I believe that the answer would be "no," because in both cases the user's browser is the party making the request. Apache might not know or be able to distinguish between two "reasons" why the browser is making such a request.
On the other hand, programmatic code within your host-side application possibly could. Either directly or using mod_rewrite tricks, you could direct the incoming request to a server-side script, which can examine the entirety of the HTTP request and determine what sort of response it should produce: image-content, or 404. In this scenario, Apache accepts the request ... does not Deny it ... but instead of serving the image directly itself, it hands-off to a script which makes that decision. (The script can still gulp the data from a file, probably from a directory that Apache will not directly serve at all, so it can be "reasonably fast.")
By the way: you can use directives, at the <Directory> or <Location> level, to force "hand this request off to such-and-such script" behavior, so that, when the user's browser "requests such-and-such image," Apache runs that handler-script instead, passing a URL that includes the name of the requested file. The user won't be able to know what actually happened.)
You can accomplish this many ways, but internet jargon this is called "hotlinking". You can use this tool http://www.htaccesstools.com/hotlink-protection/ to create your own .htaccess file.
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [NC,F,L]
I have a LAMP setup and I just want to be able to protect content on the webpage (images,css,videos,etc) so that only logged in users can access it.
I realize I can do this easily with .htaccess. However I do not want to use the authentication popup, and I want to be able to use sessions and also be able to logout.
I am using php to do the job of authenticating with mysql and create sessions. This works great. But images, css, javascript etc are still accessible.
How do I allow access to the content only if a valid php session exists?
I have come across using mod_rewrite to forward files to a php file (like auth.php?file=...) and do session checking there. This seems inefficient to check the session for every single image in a page that has already been checked. It seems like a hack and I keep thinking there is a cleaner way of doing this.
Is there a mod for apache like mod_session_cookie that could check if a cookie with a session key exists in my session database and if so sets Allow from all for the directory?
Alternatively, is it possible to use mod_auth_mysql but also be able to use sessions and login using a php form and not the authentication popup?
EDIT:
Here is my solution to the problem:
In my apache configuration file (not .htaccess) I added:
RewriteLock /var/www/lib/rewrite.lock
<VirtualHost>
#...
RewriteEngine on
RewriteMap sessionValid prg:/var/www/lib/allow.php
<Directory /var/www/client/*>
RewriteEngine on
RewriteCond %{HTTP_COOKIE} !client-cookie=([^;]+)
RewriteRule .* - [L,R=403]
RewriteCond %{HTTP_COOKIE} client-cookie=([^;]+)
RewriteCond ${sessionValid:%1} !valid
RewriteRule .* - [L,R=403]
</Directory>
</VirtualHost>
And the script allow.php:
#!/usr/bin/php5
<?php
set_time_limit(0);
echo "";
$stdin = fopen("php://stdin","r");
$db = mysql_connect(...);
mysql_select_db(..., $db);
$querypre = "SELECT ID FROM Sessions WHERE ID='";
while (1) {
$line = trim(fgets($stdin));
$query = $querypre.mysql_real_escape_string($line)."'";
$result = mysql_query($query);
if (mysql_num_rows($result) > 0)
echo("valid\n");
else
echo("0\n");
}
mysql_close($db);
?>
This works like a charm. Using this and session_set_save_handler I was able to use php sessions backed by mysql to secure both the php pages and all content within. I hope someone finds this useful.
Some caveats:
The RewriteMap statement needs to be defined inside the virtual host block if you are going to use it inside that virtual host. Placing it outside of the block will not work.
You must have set RewriteEngine on before defining the RewriteMap or it will be ignored.
RewriteLock cannot be in the virtual host block.
As with any shell script, the php file must be executable by the apache user and void of ^M's
RewriteMap statements cannot be placed in .htaccess but the other statements that use the map can.
RewriteCond %{HTTP_COOKIE} !mysessioncookie=([^;]+)
RewriteRule .+\.(jpg|css|js) forbidden.html [R=403]
I actually don't use Apache; I use lighttpd, which includes a plug-in that you can use to restrict access to a folder based on if a correct hash is passed in the URI. Basically, your application logic and the webserver share a secret salt that is then used to generate a hash with the current time, which is also passed with the hash. If the time is within the past 5 minutes, then it grants access. If not, or if the hash is invalid, then it doesn't. I'm googling around to see if there's a similar plugin for Apache at the moment.
Edit: mod_auth_token appears to do the same thing for Apache.
Instead of linking straight to the resources, use some form of controller to serve the images.
For example, linking to 'images/bob.jpg' wouldn't actually point to a resource, but a script, which checks login, and if successful, sends image/jpeg headers with the correct data.
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.
There are some scripts that I use only via ajax and I do not want the user to run these scripts directly from the browser. I use jQuery for making all ajax calls and I keep all of my ajax files in a folder named ajax.
So, I was hoping to create an htaccess file which checks for ajax request (HTTP_X_REQUESTED_WITH) and deny all other requests in that folder. (I know that http header can be faked but I can not think of a better solution). I tried this:
ReWriteCond %{HTTP_X_REQUESTED_WITH} ^$
ReWriteCond %{SERVER_URL} ^/ajax/.php$
ReWriteRule ^.*$ -
[F]
But, it is not working. What I am doing wrong? Is there any other way to achieve similar results. (I do not want to check for the header in every script).
The Bad: Apache :-(
X-Requested-With in not a standard HTTP Header.
You can't read it in apache at all (neither by
ReWriteCond %{HTTP_X_REQUESTED_WITH}
nor by
%{HTTP:X-Requested-With}), so its impossible to check it in .htaccess or same place. :-(
The Ugly: Script :-(
Its just accessible in the script (eg. php), but you said you don't want to include a php file in all of your scripts because of number of files.
The Good: auto_prepend_file :-)
But ... there's a simple trick to solve it :-)
auto_prepend_file specifies the name of a file that is automatically parsed before the main file. You can use it to include a "checker" script automatically.
So create a .htaccess in ajax folder
php_value auto_prepend_file check.php
and create check.php as you want:
<?
if( !#$_SERVER["HTTP_X_REQUESTED_WITH"] ){
header('HTTP/1.1 403 Forbidden');
exit;
}
?>
You can customize it as you want.
I'm assuming you have all your AJAX scripts in a directory ajax, because you refer to ^/ajax/.php$ in your non-working example.
In this folder /ajax/ place a .htaccess file with this content:
SetEnvIfNoCase X-Requested-With XMLHttpRequest ajax
Order Deny,Allow
Deny from all
Allow from env=ajax
What this does is deny any request without the XMLHttpRequest header.
There are only a few predefined HTTP_* variables mapping to HTTP headers that you can use in a RewriteCond. For any other HTTP headers, you need to use a %{HTTP:header} variable.
Just change
ReWriteCond %{HTTP_X_REQUESTED_WITH} ^$
To:
ReWriteCond %{HTTP:X-Requested-With} ^$
Just check for if($_SERVER['HTTP_X_REQUESTED_WITH']=='XMLHttpRequest'){ at the beginning of the document, if it's not set, then don't return anything.
edit
Here's why: http://github.com/jquery/jquery/blob/master/src/ajax.js#L370
edit 2
My bad, just read through your post again. You can alternatively make a folder inaccessible to the web and then just have a standard ajax.php file that has include('./private/scripts.php') as your server will still be able to access it, but no one will be able to view from their browser.
An alternative to using .htaccess is to use the $_SERVER['HTTP_REFERER'] variable to test that the script is being accessed from your page, rather than from another site, etc.
I have a LAMP setup and I just want to be able to protect content on the webpage (images,css,videos,etc) so that only logged in users can access it.
I realize I can do this easily with .htaccess. However I do not want to use the authentication popup, and I want to be able to use sessions and also be able to logout.
I am using php to do the job of authenticating with mysql and create sessions. This works great. But images, css, javascript etc are still accessible.
How do I allow access to the content only if a valid php session exists?
I have come across using mod_rewrite to forward files to a php file (like auth.php?file=...) and do session checking there. This seems inefficient to check the session for every single image in a page that has already been checked. It seems like a hack and I keep thinking there is a cleaner way of doing this.
Is there a mod for apache like mod_session_cookie that could check if a cookie with a session key exists in my session database and if so sets Allow from all for the directory?
Alternatively, is it possible to use mod_auth_mysql but also be able to use sessions and login using a php form and not the authentication popup?
EDIT:
Here is my solution to the problem:
In my apache configuration file (not .htaccess) I added:
RewriteLock /var/www/lib/rewrite.lock
<VirtualHost>
#...
RewriteEngine on
RewriteMap sessionValid prg:/var/www/lib/allow.php
<Directory /var/www/client/*>
RewriteEngine on
RewriteCond %{HTTP_COOKIE} !client-cookie=([^;]+)
RewriteRule .* - [L,R=403]
RewriteCond %{HTTP_COOKIE} client-cookie=([^;]+)
RewriteCond ${sessionValid:%1} !valid
RewriteRule .* - [L,R=403]
</Directory>
</VirtualHost>
And the script allow.php:
#!/usr/bin/php5
<?php
set_time_limit(0);
echo "";
$stdin = fopen("php://stdin","r");
$db = mysql_connect(...);
mysql_select_db(..., $db);
$querypre = "SELECT ID FROM Sessions WHERE ID='";
while (1) {
$line = trim(fgets($stdin));
$query = $querypre.mysql_real_escape_string($line)."'";
$result = mysql_query($query);
if (mysql_num_rows($result) > 0)
echo("valid\n");
else
echo("0\n");
}
mysql_close($db);
?>
This works like a charm. Using this and session_set_save_handler I was able to use php sessions backed by mysql to secure both the php pages and all content within. I hope someone finds this useful.
Some caveats:
The RewriteMap statement needs to be defined inside the virtual host block if you are going to use it inside that virtual host. Placing it outside of the block will not work.
You must have set RewriteEngine on before defining the RewriteMap or it will be ignored.
RewriteLock cannot be in the virtual host block.
As with any shell script, the php file must be executable by the apache user and void of ^M's
RewriteMap statements cannot be placed in .htaccess but the other statements that use the map can.
RewriteCond %{HTTP_COOKIE} !mysessioncookie=([^;]+)
RewriteRule .+\.(jpg|css|js) forbidden.html [R=403]
I actually don't use Apache; I use lighttpd, which includes a plug-in that you can use to restrict access to a folder based on if a correct hash is passed in the URI. Basically, your application logic and the webserver share a secret salt that is then used to generate a hash with the current time, which is also passed with the hash. If the time is within the past 5 minutes, then it grants access. If not, or if the hash is invalid, then it doesn't. I'm googling around to see if there's a similar plugin for Apache at the moment.
Edit: mod_auth_token appears to do the same thing for Apache.
Instead of linking straight to the resources, use some form of controller to serve the images.
For example, linking to 'images/bob.jpg' wouldn't actually point to a resource, but a script, which checks login, and if successful, sends image/jpeg headers with the correct data.