views:

196

answers:

3

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.
A: 

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.

alex
He notes that technique in his response; he's asking if there's an alternative that doesn't require a script to run for every single piece of content.
Brock Batsell
+2  A: 
RewriteCond %{HTTP_COOKIE} !mysessioncookie=([^;]+)
RewriteRule .+\.(jpg|css|js) forbidden.html [R=403]
Ignacio Vazquez-Abrams
Forgive me for not being up on my Apache-fu — is that doing any more than checking for the existence of a cookie?
Brock Batsell
@Brock: N​ope​.
Ignacio Vazquez-Abrams
Then wouldn't that be incredibly easy to circumvent? The OP wants the cookie to be verified against a proper session in his DB.
Brock Batsell
@Brock: That would require a script, either as a redirect map or as a redirect target.
Ignacio Vazquez-Abrams
This could potentially do it. As Brock mentioned, how would I verify against the session key in my DB? Or would I be forced to create and check session files with something like RewriteMap?
Luke
Verification of the session cookie value would require a script.
Ignacio Vazquez-Abrams
Ok, I'm not familiar with creating scripts for apache configuration files. How would I go about doing this and in what language?
Luke
I'd recommend writing a script for use with `RewriteMap`, but I'm not exactly sure how PHP is supposed to handle using `$_SESSION[]` when the session ID keeps changing. If you want to go this route then I recommend opening a new question for this. If you use a normal PHP script for use with `RewriteRule` then of course it just uses PHP's standard session mechanism.
Ignacio Vazquez-Abrams
Isn't that just the same as redirecting files to a php script that does session checking for each file?
Luke
A program configured via `RewriteMap` stays alive for the lifetime of the server, instead of being invoked per request.
Ignacio Vazquez-Abrams
So this program would be able to handle each incoming request that has a different session key and then just check if the key is in the database, and if it is would either allow access to the file or would give a 403? As I'm still not clear how you get apache to run such a program/script, can you point me to a link with more information?
Luke
It's just `RewriteMap` with a map type of `prg`: http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewritemap
Ignacio Vazquez-Abrams
I didn't realize RewriteMap could also execute scripts. I will see if I can make this work. Thank you very much!
Luke
A: 

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.

Brock Batsell
Unfortunately, this seems to require changing the urls, which is not an option for me.
Luke