Jump to content

[SOLVED] Protected files in user directory.


jeffjohnvol

Recommended Posts

I did a search on this topic, and found several unanswered posts:

 

http://www.phpfreaks.com/forums/index.php/topic,147677.0.html

 

http://www.phpfreaks.com/forums/index.php/topic,153734.0.html

 

http://www.phpfreaks.com/forums/index.php/topic,163423.0.html

 

http://www.phpfreaks.com/forums/index.php/topic,160112.0.html

 

Like these other developers, I'm trying to limit access to jpgs (and other files) based on a users logon.  I am using a nuke CMS, so I have a login procedure, so I know which directory they should be able to see.

 

I have also researched the .htaccess and .htpasswd topics elsewhere (http://www.javascriptkit.com/howto/htaccess.shtml) to get a understanding of htaccess.

 

My question is this:  If a user logs in, and is valid, and I have their IP address, is there a way for me to programmatically allow read access to a directory for that IP address? 

 

Also, can a server-side program such as PHP alter a .htaccess file if I code it to do so?

 

Thanks in advance.

Jeff

Link to comment
Share on other sites

My question is this:  If a user logs in, and is valid, and I have their IP address, is there a way for me to programmatically allow read access to a directory for that IP address?

 

Short answer:  Yes.

Real answer:

 

The best way it would seem to me would be to make users get files through a PHP file....  Like:

http://site.com/files.php?user=Corbin&file=omgpicture.jpg

 

(Yes, PHP can mod any files on the server that it has write access to.)

 

Oh, you could even mod_rewrite it up so:

 

http://site.com/files/Corbin/omgpicture.jpg would redirect to http://site.com/files.php?user=Corbin&file=omgpicture.jpg

If you did it this way, the files would be stored out of the web root.

Example, if your webroot was /sites/site.com/html/, you could store the files in /sites/site.com/user_files/

Then, the PHP file would output the file to them after checking their authorization and what not.

 

If that's how you want to do it, I'll explain more.

 

 

If you did it with htaccess, it could quickly become bulky.  I'm hoping someone else will have a better idea, but this would work....

Link to comment
Share on other sites

The best way it would seem to me would be to make users get files through a PHP file....  Like:

http://site.com/files.php?user=Corbin&file=omgpicture.jpg

 

(Yes, PHP can mod any files on the server that it has write access to.)

 

Oh, you could even mod_rewrite it up so:

 

http://site.com/files/Corbin/omgpicture.jpg would redirect to http://site.com/files.php?user=Corbin&file=omgpicture.jpg

If you did it this way, the files would be stored out of the web root.

Example, if your webroot was /sites/site.com/html/, you could store the files in /sites/site.com/user_files/

Then, the PHP file would output the file to them after checking their authorization and what not.

 

If that's how you want to do it, I'll explain more.

 

Okay, I can see how I could write a php program to determine if the two inputs (user id and file) were valid, and echo a link to a file, but at that point, wouldn't the file be viewable by the world if they had the address?  Perhaps I'm not understanding what the file.php program would do, but I'm interpretting it as evaluating permission and echo'ing a page that has the file listed as a url?

 

Thanks.

Jeff

Link to comment
Share on other sites

Noooo, the file.php page wouldn't give a link to the file; it would give the actual file.

 

For example, let's say I had my web root at /site/corbin/html/, meaning something like http://mysite.com/file.txt would look for /site/corbin/html/file.txt.  Now, let's say I had the file secret_file.txt in /site/corbin/, a PHP file could show this like follows:

 

<?php
if(isset($_GET['pwd']) && $_GET['pwd'] == 'omgimcorbin')) { //if the page was accessed with ?pwd=omgimcorbin
if(false !== ($fh = fopen('../secret_file.txt'))) {
	//These headers would make the page not be cached by the web browser
	header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
	//this would tell the browser to download it instead of showing it
	header("Content-type: application/octet-stream");
	header('Content-Disposition: attachment; filename="secret_file.txt"'); //suggest a filename
	while(!feof($fh)) {
		echo fread($fh, 1024); //read and echo [up to] 1024 bytes at a time
	}
}
else {
	echo "Unable to open the secret file!";
}
}
?>

 

That way, the file wouldn't be accessible straight through http://mysite.com/secret_file.txt or anything similar, but if someone supplied the correct password he could still get it.

 

That could be expanded to check for user name and what not in your case.

Link to comment
Share on other sites

Corbin, Okay, I get it now.  That would take care of the basic function.  So basically, the browser would allow them to view/save the file based on the user id.

 

You have answered my question, Thanks!

 

To expand the question just a bit, this wouldn't work in terms of displaying multiple files on a page for say like thumbnails would it?  I suppose thumbnails could be constructed (somehow, I can research) and the url's on the thumbnail would have the structure you are talking about.  The thumbnails wouldn't be secret, just the larger version of the file.  Let me know if that confuses.

Link to comment
Share on other sites

<img src="files.php?file=thumb_image1.jpg" />

 

Then files.php something like:

 

session_start();
if(!isset($_SESSION['userid']) || !isset($_GET['file']) exit;
$dir = '../' . $_SESSION['userid'] . '/';
$file = $_GET['file'];
if(preg_match('/[a-zA-Z0-9_ -]{1,255}/', $file)) { //very restrictive file names...  I probably wouldn't actually use this, but for an example it's fine
     //pretend the loop from earlier is here
    //if(false !== ($fh = fopen($dir . $file))) {
}

 

So, if I was logged in and my userid was 1, that would show me 1/thumb_image1.jpg.

Link to comment
Share on other sites

Oh, I get it, the img source would reference the files.php and it would do the evaluation.  Thats genius.  Thanks Corbin, youdaman!

 

Is there a way for someone to hack it by spoofing the session id value of userid to one of the known users to get around this?

 

BTW, The info you gave here is very useful.  It might be worth putting in the code snippet /common faq section.

Link to comment
Share on other sites

$_SESSION['userid'] would be set on the login page like:

 

if($_POST) {
//mysql_connect()
//session_start()
$username = (isset($_POST['username'])) ? $_POST['username'] : null;
$password = (isset($_POST['password'])) ? $_POST['password'] : null;
if($username == null || !preg_match('/[a-zA-Z0-9_]{1,16}/', $username)) {
	echo 'Please enter a 1-16 character alphanumeric username (_ allowed).';
}
elseif($username == null || !preg_match('/[a-zA-Z0-9_]{1,16}/', $password)) {
	echo 'Please enter a 1-16 character alphanumeric password (_ allowed).';
}
else {
	$user = addslashes($username);
	$password = md5($password);
	$q = mysql_query("SELECT userid FROM users WHERE username = '{$user}' AND password = '{$pass}' LIMIT 1");
	if(mysql_num_rows($q) != 1) {
		echo 'User was not found or the password was incorrect.';
	}
	else {
		$r = mysql_fetch_assoc($q);
		$_SESSION['userid'] = $r['userid'];
	}
}
}

 

 

So... unless they hijack someone else's session (the actual session ID) or they know someone's password, the files are secure.

 

 

Oh, this might be worth mentioning....

 

With images, the content isn't likely to change, so caching might be useful to lower bandwidth, but that would mean someone on the same computer might find them in the browser cache....

 

Oh, also with images, you could make it so users could upload images, and then the php script would do something liek the following:

 

//pretend $user and $file are set
if(isset($_GET['thumb']) && $_GET['thumb'] == '1') {
    if(file_exists('../thumbs/' . $user . '/' . $file)) {
         //output file
    }
    else {
          if(file_exists('../images/' . $user . '/' . $file)) {
                 //generate, save to disk, and output thumb
          }
          else {
                //invalid file; do nothing
          }
    }
}

 

 

(P.S.  Coded both of these in like 30 seconds, so no telling if they're messed up or not)

Link to comment
Share on other sites

  • 2 weeks later...

Corbin, I hope you are still out there.  I'm trying this and I have removed any authentication from the user at this point, I'm just trying to see if I can send a file with a "file.php" program I have created a php file called file.php with the following:

 

<?php

if(isset($_GET['file'])) {

$file="modules/Ads/images/sigs/testuser3/".$_GET['file'];

if(false == ($fh = fopen($file))) {

//These headers would make the page not be cached by the web browser

header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past

//this would tell the browser to download it instead of showing it

header("Content-type: application/octet-stream");

header('Content-Disposition: attachment; filename="secret_file.txt"'); //suggest a filename

while(!feof($fh)) {

$out=fread($fh, 1024); //read and echo [up to] 1024 bytes at a time

echo $out;

}

}

else {

echo "Unable to open the file!  $file";

}

}

 

?>

 

Then I try to call it with:

 

http://www.loghomecorner.com/modules/Ads/file.php?file=back_porch2.jpg

 

but I get:

 

Error 500 - Internal server error

An internal server error has occured!

Please try again later.

 

Is reading an image file piece by piece and outputting it to the window the wrong thing to do?

 

Link to comment
Share on other sites

if(false == ($fh = fopen($file))) {

should be

if(false !== ($fh = fopen($file))) {

 

Also, try turning error reporting on to see what it says.

 

Add error_reporting(E_ALL); to the top of the code please.

 

Also, htaccess can cause 500 errors, so it might be worth checking apache error logs.

Link to comment
Share on other sites

Corbin, I think you got me through it.  I initally thought the !== may have been a typo, so I just went with == because I was certain the file name was right, when in fact it wasn't.  I had to add the "http://www.mysite.com...." to the front for the file to be valid.

 

The caching statements were giving an issue, so I commented those out, and then it worked fine after that.  I'm not real concerned about the caching, so its not a big deal.

 

Now that I have the base file.php working, I can play with the directory permissions and my user testing.

 

Thanks again.

Jeff

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.