Solved

Can't access a file in a folder protected by .htpasswd/.htaccess

Posted on 2006-07-17
17
608 Views
Last Modified: 2012-08-13
Hi experts

I'm stuck again! I have confidential user information in a folder that is protected by .htaccess and .htpasswd files which is working fine. Thing is, when I try to include images from this folder in a webpage built by the heredoc feature of PHP, a login box appears before the page does.

Is there a way of specifying a username/password to allow the image to be included on the page or is there a better way round it?

Also, is it safe to put .htaccess/.htpasswd only in the first level of folder protection required or should these files be in all subfolders too in order to protect those subfolders?

EG:  /topfolder/nextfolder
  to protect both levels, should the .ht files be in both folders or just /topfolder/ ?

Thanks
DC
0
Comment
Question by:davidcowler
  • 7
  • 5
  • 4
  • +1
17 Comments
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 17127581
Have a look at this:
http://bg2.php.net/features.http-auth
it shows you how to authenticate in order to get the files.

It is good enough to have .htaccess/.htpasswd in the first level folder. It applies to all subfolders. Of cource if you need different settings you have to put separate files in the subdirectories.
0
 
LVL 9

Expert Comment

by:cristi_2112
ID: 17128687
Hello,

If you want to protect some information on your server, you should protect ONLY that information. It is not a good technique to put confidential information and public images into the same folder protected with .htaccess; because then you have to make workarounds for displaying the images and this is not ok.
You should put ONLY the confidential information (the info that really needs authentication to be displayed) into the .htaccess-protected folder, and the images and all things that are public, in other folders.
0
 
LVL 1

Author Comment

by:davidcowler
ID: 17133381
Ivanov_G, do you understand the page you directed me to? I'm not sure I do! It seems to want to access a web page whereas I want it to access an image. Maybe I've altered the path incorrectly?

if ($source = get401Page('/absolute/path/file.php?get=value')) {

This suggests it's looking for a PHP file with a GET variable. I don't understand what I need to change this to. If I'm looking to access pic1.jpg for example and the path is /mydomain/members/images then should the above be:

if ($source = get401Page('/mydomain/members/images/pic1.jpg?get=value')) {

???

Thanks for help so far.
DC
0
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 17133630
If you have .htpasswd in /mydomain/members/images/, it apply to all files and subdirectories. So in order to get the image, you have to authenticate with username/password. Look at the examples on the URL I gave you.
0
 
LVL 1

Author Comment

by:davidcowler
ID: 17134979
This isn't helping I'm afraid. Those examples seem to all be about giving then user a popup box to login with. I don't want that. I just want to be able to say, this is the image i want, it's in this folder, username and password for which is x and y, let me display it within my page. It's got to be a one-liner, surely? Otherwise I'm very quickly going to be losing my faith in PHP.

I've tried setting $PHP_AUTH_USER and $PHP_AUTH_PW and beyond that I don't know what to do with it. I get a blank image. If I right click to "show image" I get the login box. If I login the picture shows. The authentication MUST be invisible to the user. Using the two headers as shown in the example always gives the login dialog box. I never want to see it.  

Any ideas?

???? ;(
0
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 17136971
http://bg2.php.net/features.http-auth
Example 34-2. Digest HTTP Authentication example

Take a look at the example. It is exactly HTTP authentication example - what you need
0
 
LVL 1

Author Comment

by:davidcowler
ID: 17141234
I haven't got the time or the patience to fathom that code out. It's got a pop up box in it and it's checking a username and password. I KNOW what the username and password is, it doesn't need checking, I just need to tell the server that. That code doesn't even specify where the file is! No domain, nothing!

This stuff is just gonna have to go in an unprotected folder unless anyone can explain this to me or has any other bright ideas. I can upload images to the folder without a problem. Only hitting a brick wall when trying to retrieve them.
0
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 17141282
The Authentication is set in $_SERVER['PHP_AUTH_DIGEST'], so you are logged and don't get the popup box when you request a file.
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 1

Author Comment

by:davidcowler
ID: 17150634
I still haven't got the time to figure out that chunk of code. I tried the following, which did not work. (note i have removed the part that sends the headers and moved the function to the top of the script). Program stops at point 1a. I do not believe that this code runs as a standalone script. I mean, how do you specify a password?

I have tried to set the username before the PHP_AUTH_DIGEST thing but it seems to need info from that call before it will work, but the AUTH_DIGEST won't work without a username.

All I really want is a couple of lines of code that say "have this username and password and let me have the image files in return". It can't be done, can it?

<?php
$realm = 'Restricted area';

//user => password
$users = array('myusername' => 'mypassword');

// function to parse the http auth header
function http_digest_parse($txt)
{
   // protect against missing data
   $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
   $data = array();

   preg_match_all('@(\w+)=([\'"]?)([a-zA-Z0-9=./\_-]+)\2@', $txt, $matches, PREG_SET_ORDER);

   foreach ($matches as $m) {
       $data[$m[1]] = $m[3];
       unset($needed_parts[$m[1]]);
   }

   return $needed_parts ? false : $data;
}

$users[$data['username']] = 'myusername';  //<why does this not set the username?


// analyze the PHP_AUTH_DIGEST variable
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
   !isset($users[$data['username']]))
   die('Wrong Credentials! 1a');


// generate the valid response
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);

if ($data['response'] != $valid_response)
   die('Wrong Credentials! 2a');

// ok, valid username & password
echo 'You are logged in as: ' . $data['username'];

?>

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>New Page 1</title>
</head>

<body>

<p><img border="0" src="/members/photos/123.jpg" width="193" height="266"></p>

</body>

</html>


0
 
LVL 5

Accepted Solution

by:
floorman67 earned 150 total points
ID: 17167550
simply place any public accessible files in a folder and .htaccess its subfolders for private access.

you can not automate http authentication via script ... for very good reasons ... it would create a huge security hole and open the door to brute force scouting, flooding, xxs, and injection vulnerabilities.

it requires manual input.

there is a way to punch through any .htaccess with php but that is only in the case of file downloads and socket streaming of data, but not to display via a web browser under the http protocol.


0
 
LVL 5

Expert Comment

by:floorman67
ID: 17167602
for instance, in a .htaccess/.htpassword protected directory folder,  you can open up a file with php, like a mp3 file, and stream it to a flash player embedded in a web page, and furthermore you can for any file for a direct download routed through php then stream it through php to the client becasue the server is asking for it, not the client.

But you can not ask for it DIRECTLY through the client via html output.

see the difference ?

so no .. it cant be done.

0
 
LVL 1

Author Comment

by:davidcowler
ID: 17170696
Hi Floorman67

Thanks for your input. What I actually have is a folder of images which I don't want people to be able to access willy-nilly. For example, if you know the path and filename (which you can easily get by right clicking and choosing "properties") then you can put that straight into a browser and get the image. The php code builds a web page using the heredoc feature and tries to drop the paths to the images within it - but that's where it asks for authentication.

Now I know this can't be done I'll probably give the images "random" filenames so they can't be guessed if you know one (they are in sequences so you can guess the next filename).

Is there any clever way of disabling right click by the way? That would help too.

Thanks
DC
0
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 17170837
Another solution, I don't know if it will work, but just to mention it:
Create a file, let's say displayimage.php which will take a parameter: displayimage.php?img=7056

The id 7056 will tell you which image you have to open (you will define it by your own). Make your images readable by 127.0.0.1 ONLY.

In displayimage.php something like:

<?
  $id = $_GET['img'];
  $imagePath = 'SOMETHING_YOU_DETERMINE_HERE';
  header ("Content-type: image/jpeg");
  readfile($imagePath );
?>

I wrote it by memory. Not sure if it works, but You got the idea.

You can also check some $_SESSION variable in displayimage.php to make sure the file is not called directly like the example you gave above and then

<img src="displayimage.php?img=1234" ...
0
 
LVL 5

Expert Comment

by:floorman67
ID: 17173353
as per your request, here is an example of removing click and drag and right click capabilities from your web page within the <BODY> HTML tag.

<body oncontextmenu="return false" ondragstart="return false" onselectstart="return false">

and as to the other request and the information the other guy posted,

what you are talking about is two different things.

on the on hand, you are talking about a forced download routed through php, which is a SERVER SIDE REQUEST and CAN punch through any .htaccess/.htpassword protection becasue the permissions are absolute becasue the server has permissions for everything locally.

On the other hand, you are talking about a client request for information to be dispayed on a web page in a client browser via the browser and you can not automate the process from a server request becasue it is the client browser making the request TO the server (which requires authentication) for data.

There is an inherent security risk here for forced downloads and it will not automatically display the data but instead a download box.

even wrapping it in php with with a data tag ID# it can not be done, and the absolute path will show in properties and in the temporary internet cache.

The browser needs the absolute path and can not punch through .htaccess from a client request that isnt a forced download with a popup confirmation  routed through php.

The thing is that it requires some action on the user or any web page could use server side script to open anything on a client browser/machine and possibly run or display malicious content.

even IF you run it through php to punch through any .htaccess/.htpassword protection, there is still client side browser USER SECURITY to think about ... and they are protected form displaying any automated content without some kind of user action like clicking to accept the forced download or disabling images or objects embedded and forcing the user to refresh the page to get the content ... user action is needed.

Here is an example :

I set up this web page for you as an example: http://obscurity.ws/SECURE_DOWNLOAD_SCRIPT/

if you click this it will display some protected downloads.

it also attempts to automatically display an image using the protected download URL (as the gentleman above suggested using an ID# but I used an ID string).

as you can see the real file location is hidden and no one can get it.

as you also will see I tried to automatically place and image on the web page using the <IMG> tag and it at first shows you a disabled image until you refresh the page (manual user action required), then it is stored in the temporary internet cache, so this wouldnt be a valid production solution because when the user first enters your site they will be greeted with a disabled image.

In conclusion, while routing files through PHP is an excellent solution for some forms of content and resource protection, it does not serve as an adequate protection for automatic image placement on web pages for production sites becasue of the manual input required to see them in the first place.

HOWEVER there are certain things you can do with some fancy javascript to overlay a transparent image so when they right click the image they save the transparent one, but this solution is  a waste if you are using an anti right click I posted, and they can always get it from the cache.

Hotlink protections is probably your best bet.
0
 
LVL 5

Expert Comment

by:floorman67
ID: 17173389
ok i just retested it a few times, clearing my cache between uses, and sometimes i got the red x disabled image until i refreshed the page and sometimes I didnt ... very strange.

Play wiith it a while if you want and see if its an adequate solution for you.

Might be my server configuration.
0
 
LVL 1

Author Comment

by:davidcowler
ID: 17359008
Still got to try this... have been away for a while. Adjudicators - please don't close this one yet. Thanks :)
0
 
LVL 1

Author Comment

by:davidcowler
ID: 17410492
Ok, I don't need to "hide" all the images if I give them random filenames, so that kinda solves that. I also realised that putting an index.php in a folder will prevent a client browser from displaying the file contents of that folder and the index.php script can simply redirect the user to the home page or a "you can't do that you spotty oik" page.

I am awarding the points to floorman67 as he ended the wild goose chase by pointing out that the authentication I was looking for isn't possible for security reasons.

Thanks for all contributions :)
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Consider the following scenario: You are working on a website and make something great - something that lets the server work with information submitted by your users. This could be anything, from a simple guestbook to a e-Money solution. But what…
Foreword (July, 2015) Since I first wrote this article, years ago, a great many more people have begun using the internet.  They are coming online from every part of the globe, learning, reading, shopping and spending money at an ever-increasing ra…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now