Forum Moderators: phranque

Message Too Old, No Replies

Apache / PHP Login Script

Disable access to all files except index.php

         

NCerch

6:51 pm on Jan 13, 2005 (gmt 0)

10+ Year Member



Hello everyone,
Thank you in advance for your knowledge. I have written a php script that allows access to specific .html pages if they pass the data validation, by the use of:

header("Location: blah.html");

What I would like to accomplish is to deny access to everything on the server unless they pass through the login screen.

Example: A remote user can not type in 192.182.82.83/folder/file.html and have it display, unless they pass through 192.182.82.83/folder/index.php

index.php = login page

NCerch

8:21 pm on Jan 13, 2005 (gmt 0)

10+ Year Member



I am not sure if this is going to work, but I am trying to password protect the root directory. I have added the .htaccess file and the .htpasswd file to the root directory (where my index.php is located), but when I access the site, I dont get any htaccess password screen. I just get the index.php page, just as I normally do. Any advice would be appreciated.

Thanks.

jdMorgan

12:06 am on Jan 14, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



NCerch,

Welcome to WebmasterWorld!

You might want to post the part of your .htaccess code relevant to authorization. Lacking that, all I can do is to suggest that you read the Apache Authentication, Authorization, and Access Control [httpd.apache.org] tutorial.

Jim

jatar_k

12:14 am on Jan 14, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Welcome to WebmasterWorld NCerch,

there are methods to doing this with php using sessions as well.

or maybe this would help
HTTP authentication with PHP [php.net]

RedScourge

10:35 am on Jan 14, 2005 (gmt 0)

10+ Year Member



a good way to make all the pages return to the login page if the user is not logged in is to add a session/cookie checking function call to every page, i.e. import a file that has a checkSession() function and run it.

i will post you some example code from the sort of thing you probably want, it uses sessions in php, using $_SESSION to add session data, etc:

function checkSession(){
//these variables would be defined somewhere else
global $timeout, $dbhost, $dbtable, $dbuser, $dbpass, $dbname;
session_start();

if(!isset($_SESSION['ip'])){//either session is not set
session_destroy();
header("Location: ".getHeader("login.php?msg=no_sess"));
exit;
}
else if($_SESSION['time']+$timeout < time()){//or its exipred

//mark them offline duh!
$user=$_SESSION["user"];
$time=time();
$link = @mysql_connect($dbhost,$dbuser,$dbpass) or die("Could not connect to database");
mysql_select_db($dbname, $link) or die("Could not select table $dbname");
$query="UPDATE $dbtable SET online='0', sid='0', sidtime='0', logouttime='$time' WHERE user='$user'";//
$result=mysql_query($query, $link);
mysql_close($link);

session_destroy();
header("Location: ".getHeader("login.php?msg=sess_exp"));
exit;
}
else if( getTwoOctets($_SESSION['ip'])!= getTwoOctets($_SERVER['REMOTE_ADDR']) ){//or not on right ip
session_destroy();
header("Location: ".getHeader("login.php?msg=ip_addr&valid=".getTwoOctets($_SESSION['ip'])));
exit;
}

else{ //or everything is fine, return username we are logged in as
$_SESSION['time']=time();
$time=time();

$user=$_SESSION['user'];

//then update the sidtime to current
$link = @mysql_connect($dbhost,$dbuser,$dbpass) or die("Could not connect to database");
mysql_select_db($dbname, $link) or die("Could not select table $dbname");
$query="UPDATE $dbtable SET sidtime='$time', WHERE user='$user'";
$result=mysql_query($query, $link);
mysql_close($link);

return $_SESSION['user'];
}
}

basically how that system works, is you define some constants, like a page to go when there is no session data in the header (i.e. user didnt log in), if a time vlaue stored in the session that determines if their session is terminated has expired, if their ip address does not match the one allocated to that session (you might wanna just match it to 2 octets instead of all 4 so that users from big proxies like AOL whos IP's change alot can still access the pages and not get logged out every time the log in) i think i have a method getHeader that generates a [address...] full canonical name as well, thats easy enough to do as well.

this text may end up really weird formatted in this chat, and hopefully its not too long.

its just a sample of a REALLY quick and dirty login system i was making, so i wouldnt recommend you use it for anything of the utmost importance.

but you might consider thinking about it anyways, think of how it works perhaps.

RedScourge

10:41 am on Jan 14, 2005 (gmt 0)

10+ Year Member



my example uses a database and php, it doesnt really use apache's stuff at all, if you wanted to use apache you would have to do something like this in your .htaccess or httpd.conf:

<Directory "C:/Program Files/Apache Group/Apache/htdocs/priv">
Options Indexes IncludesNOEXEC SymLinksIfOwnerMatch MultiViews
AllowOverride None
AuthName "priv"
AuthType Basic
AuthUserFile "C:/Program Files/Apache Group/Apache/users/.htpasswd"
require valid-user
<Limit GET POST>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>

this would block everything in the priv folder, and you could have your login thing be in a directory below it, either that or you can have them all in the same directory and use a <files> directive or something.

as for forwarding the user to the login page if they try to access an authentication requiring page, perhaps you could in the .htaccess set a HTTP 403 ErrorDocument page to be the login page, that would mean if you get the Authorization Required error (by not logging in when apache prompts you to) it would forward you to the login page.

i dont know how well that would work for you, but hopefully it isnt totally useless.

NCerch

3:36 pm on Jan 14, 2005 (gmt 0)

10+ Year Member



Thank you all over your detailed responces. I really appreciate it. I have decided to move all the client folders to a different drive so that the entire server is not open. I have yet to solve the problem of being able to access everything on the new drive. I think I have a solution, but I am not sure. What I am trying to do now is to have the user login through the php script, which will direct them to their company.html file (displays links to their folder). Can I add an additional .htaccess file to their folder which, once they pass the php script, will require them to enter their password again to access the folder?

Thank you so much.

NCerch

3:54 pm on Jan 14, 2005 (gmt 0)

10+ Year Member



Is it possible to have multiple "<directory></directory>"'s in the httpd.conf file?

If so, then I believe that I need to add 3 more "<directory>" instructions in the httpd.confg to correspond to the client folders.

At that point I need to add the code inbetween the <directory> and </directory>.

That is the part that I do not know anything about.

I would appreciate any help.

I currently have:

<Directory "D:/">
Options Indexes FollowSymLinks
# Options FileInfo AuthConfig Limit
AllowOverride None
Order allow,deny
Allow from all
</Directory>

NCerch

4:07 pm on Jan 14, 2005 (gmt 0)

10+ Year Member



Ok, I believe that will work (what I last posted)....But when I add this code:

<Directory "D:/testing">
Options Indexes IncludesNOEXEC SymLinksIfOwnerMatch MultiViews
AllowOverride None
AuthName "Blah Blah Blah"
AuthType Basic
AuthUserFile "C:/password/.htpasswd"
require valid-user
<Limit GET POST>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>

The password screen comes up, but will not accept the username and password.

.passwd file contents:
Testing:4NqkxqpKjbnlo

Thank you.

NCerch

4:41 pm on Jan 14, 2005 (gmt 0)

10+ Year Member



I hate to keep posting, but I am encountering small problems. I am still having the above problem, but I am also having a seperate problem.

When the .htaccess login fails, I would like to redirect the user to the index.php page.

Currently it will, but the in the Internet Explorer address area, it still reads [xx.#*$!.xxx.xx...] and by clicking directly on it will take you to testing.html

I would like for it to redirect to the index.php page, and for the address to read [xx.xxx.xx.xx...] or [xx.xxx.xx.xx...]

Current httpd.conf error addition:

ErrorDocument 401 /index.php

Thank you for your help.

NCerch

5:33 pm on Jan 14, 2005 (gmt 0)

10+ Year Member



The error I am getting with the first problem (login not working) is:

[Fri Jan 14 12:22:58 2005] [error] [client blah.blah.blah.blah] (OS 3)The system cannot find the path specified. : Could not open password file: D:/password/.htpasswd, referer: [blah.blah.blah.blah...]
[Fri Jan 14 12:22:58 2005] [error] [client blah.blah.blah.blah] user Testing not found: /testing/testing.html, referer: [blah.blah.blah.blah...]

blah = ip address

Thank you in advance for your help.

RedScourge

4:51 am on Jan 17, 2005 (gmt 0)

10+ Year Member



i dont know what you mean with your last post, but ill tell you a bit about using a <directory> directive in the httpd.conf.

you CAN point to a seperate drive, or seperate folder that is outside your server root, usually the htdocs folder, by doing something like this:

make a folder somewhere inside the web root (i.e. "htdocs/private") then you can do something like this: (*note that aliases only, not <directory> directives, have slashes at the end)

Alias /private/ "D:/private/"

then you can access it with a <directory> directive like this:

<Directory "D:/My Music">
...
</Directory>

and basically what happens is the user is able to go to your "/private" folder on your D: drive (assuming windows) but it will tell them they are at [yourwebsite.com...]

you have to do that alias stuff so that apache knows to allow you access to it, otherwise, your configuration most likely restricts the access of your other harddrive, for example:

<Directory />
Options SymLinksIfOwnerMatch
Order allow,deny
Deny from All
AllowOverride None
</Directory>

if you have something like that (apache's default config has a <Directory /> directive that limits access to folders other than your web root (htdocs) and folders inside it.

RedScourge

5:01 am on Jan 17, 2005 (gmt 0)

10+ Year Member



yeah i think your error saying that it cant find the file ON THE D DRIVE might have to do with the Alias stuff i told you about. if i was having a passworded folder on a drive different than my c drive i would do this:

<Directory "D:/Apps">
Options Indexes IncludesNOEXEC SymLinksIfOwnerMatch MultiViews
AllowOverride None
AuthName "fileshare"
AuthType Basic
AuthUserFile "C:/Program Files/Apache Group/Apache/users/.htpasswd"
require valid-user
<Limit GET PUT>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET PUT>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>

oh and also, what you want for it to direct you to index.php when you get a 401 is this:

ErrorDocument 401 /401.php

401.php:

<?php

Header("Location: [yourwebsite.com...]

?>

You probably know that the Header function (claims in the documentation at least) that you have to provide it with a full canonical URL address.

i would use a function like this to generate this full canonical name for any given page:

$domainname would be used if you have a www address, and if not you would leave it blank and it would make you a [ip.address.here.x...] style address, or with a port number in it if you use your server on a port besides port 80. $protocol is just the "http" or "https" part of the address you would want it to use.

function getHeader($page, $protocol){
$domainname=""; //if you use a www.com name set this to "www.domainname.com/" or else if you use an ip address leave it blank
if(!isset($domainname) ¦¦ $this->domainname==""){

if(!isset($protocol) ¦¦ $protocol=="")
$protocol="http";
if($portnumber!=""){
return $protocol."://".$_SERVER["SERVER_ADDR"].":".$_SERVER["SERVER_PORT"]."/";
}
else{
return $protocol."://".$_SERVER["SERVER_ADDR"]."/";
}
}
else{
return $domainname;
}
}

hopefully this big mess of code turns out readable when i post it.

RedScourge

5:09 am on Jan 17, 2005 (gmt 0)

10+ Year Member



whoops i have a $this->domainname instead of $domainname in there.

thats because i grabbed that code from a php object class that uses instance variables and functions and i forgot to change all the variables to make work in a simple function.

im currently working on a system that would let my users log into a page on my site, then once they log in, they are able to get into my htpasswd protecteed directories, but since i dont have index pages for them i have no way to protect the files from non-users currently, im thinking i might have to make a php script that indexes an entire directory that is above the htdocs directory so apache cant access it, and making the script serve the files, but id rather not do that.

also this script is going to allow my users to log into any of the games on my site i plan to make in the future, and make it so they dont have to enter different passwords, their game accounts all would let them in with their global site login.

im far from a pro at the whole authentication and security thing, but unless my site gets hit by a real cracker, i probably have nothing to worry about, and i hope you realize that any setup you do if youre not a pro at this stuff is bound to have some holes in it somewhere. i would recommend you aim towards simplicity when choosing between simplicity and complex-but-secure-if-it-works ways of thinking.