tags:

views:

515

answers:

6

I am working on my first PHP based website, and I was wondering what solutions were out there for a username/password system? I have tried using a .htaccess file for basic security, and while it works, I want something a little easier for a layman to administer. Are there any other solutions out there that I could try? I don't have a database server available, so it would have to support flat file databases...thanks!

Edit I have determined that I do have SQLite support, so I do have a database option available. Also, I feel I should mention a little further some requirements that I have. I originally looked to using .htaccess to protect my website, since I need security over the entire directory. Most of the files I am trying to protect are .pdf and .doc...any solution would have to allow me to secure those files as well as any web pages in the directory.

If I could find a good solution to more or less "skin" the .htaccess method of locking a directory, so that I could do things like have an actual login/register page, etc. then I would just stick to the .htaccess method. I would however like something that is more manageable, I just need the directory security.

+1  A: 

Sure, there are plenty of flat file database PHP security systems available. Doing a quick Google search will pull up many results. Here is a tutorial:

http://www.devshed.com/c/a/PHP/Private-Pages-with-PHP-and-Text-Files/

James Skidmore
That looks pretty good, but I was hoping for directory level security, and I wanted a registration form type deal as well. I suppose these things wouldn't be all that hard to code myself, I'm just pretty new to php and didn't want my client (so to speak) to have to wait a long time for me to learn how to code the php!
sunmorgus
+1  A: 

Check if you have support for sqlite, it doesn't require a server so it might work for you.

And don't forget to hash your passwords. ;)

To check create a file (ex. php_info.php) add:

<?php
     phpinfo();

Then upload the file to your host, load it in your browser (example.com/php_info.php) and do a search for sqlite.

You should see several references to sqlite in the page that shows if you have support. The line with "SQLite Library" will tell you the version of sqlite you have (if you have it).

Also once you are done you should delete the php_info.php file from your site, since it does give some information on your setup which can be helpful to crackers.

MitMaro
haven't thought about sqlite...i will look into that one, thanks!
sunmorgus
how would i find out from my host whether sqlite was supported?
sunmorgus
Updated my post with info on how to check for support.
MitMaro
I will give that a shot tomorrow and report back on that
sunmorgus
It would appear as though I do have sqlite support...version 3.3.7...this just got more interesting!
sunmorgus
If you got sqlite then I would highly recommend it over a flat file as it should be much faster and wouldn't require you to write the read and write methods. Another issue with a flat file is that if you have user registration then having two or more php process writing to the file at the same time could cause file curruption.
MitMaro
Yeah...I will definitely shift my focus to using SQLite, now that I know it is available to use.
sunmorgus
I was wrong...no sqlite support...xml files it is! Thanks!
sunmorgus
A: 

have you seen if you have SQLite available? It is PHP's built in database. If not you could just use read/write to a file hope this helps a bit

Marc Towler
+1  A: 

I wrote up this code quickly, it is syntacticly correct but I have not tested it.
There are 2 things that I did not do here, first, I did not provide a function to remove a user and second I did not provide a function to change a users password, these you'll have to write yourself.
However this should provide for a good place to start.

These functions will store your usernames/passwords in a file called passwords in the following format

username0:password0
username1:password1
username2:password2
...

.

function authenticate($username, $password)
{

    //ALWAYS use a salt to secure the encryption of your passwords, this can be any value of any
    //length, the longer and the more characters the better
    //I like to use a "perfect password" from Steve Gibbson's https://www.grc.com/passwords.htm
    //This must the exactly the same as the salt in theaddUser() function
    $salt = 'voDeaFWckErOPPGwiapYBwEoc4O2d1M60m2QsYc7A15PUshrLamoVioG1wUmEgF';

    //First we need to get the contents of the file that has the usernames/passwords in it.
    //we don't want to use fopen() or we may end up with a locked file error if another access is 
    //attempted before we've closed it.

    //this line will get the contents of the file named passwords and store it in the $fh variable
    $fh = file_get_contents('passwords');

    //Now lets take the file and split it into an array where each line is a new element in the array.
    $fh = split("\n", $fh);

    //Now lets loop over the entire array spliting each row into it's username/password pair
    foreach($fh as $r)
    {
     //Every time this loop runs $r will be populated with a new row

     //Lets split the line into it's username/password pairs.
     $p = split(':', $p);

     //Since we don't need all the usernames/password to be in memory lets stop when we find the one we need
     if($p[0] == $username && $p[1] == sha1($salt . $password))
     {
      //We've found the correct use so lets stop looping and return true
      return true;
     }
    }
    //If we've reached this point in the code then we did not find the user with the correct password in the 'database'
    //so we'll just return false
    return false;
}
function addUser($username, $password)
{
    //ALWAYS use a salt to secure the encryption of your passwords, this can be any value of any
    //length, the longer and the more characters the better
    //I like to use a "perfect password" from Steve Gibbson's https://www.grc.com/passwords.htm
    //This must the exactly the same as the salt in the authenticate() function
    $salt = 'voDeaFWckErOPPGwiapYBwEoc4O2d1M60m2QsYc7A15PUshrLamoVioG1wUmEgF';

    //We need to parse out some preticularly bad characters from the user name such as : which is used to seperate the username and password
    //and \r and \n which is the new line character which seperates our lines
    $username = preg_replace('/\r|\n|\:/', '', $username);

    //Now lets encrypt our password with the salt added
    $password = sha1($salt . $password);

    //Lets build the new line that is going to be added
    $line = $username . ':' . $password . "\n";

    //Lets open the file in append mode so that the pointer will be placed at the end of the file
    $fh = fopen('passwords', 'a');

    //Write the new entry to the file
    fwrite($fh, $line);

    //Close the file
    fclose($fh);

    //Typicaly one would write a bunch of error handling code on the above statments and if something
    //goes wrong then return false but if you make it this far in the code then return true
    return true;
}
Unkwntech
If you do go the flat file method make sure your password file is not web accessible. Either place it out side of the web directory (typically www orhtdocs) or deny access in your .htaccess file. :)
MitMaro
Better use a unique, random salt for each entry.
Gumbo
@Gumbo: How exactly would that work? You need to know the salt when validating the user. If the salt is random then you wouldn't know it to be able to check the users password.
MitMaro
@MitMaro: You can put it in the file also against each user.
Tom Haigh
@Tom Haigh: Place the salt in the file? This completely defeats the purpose of the salt.
MitMaro
@MitMaro: Easy, store passwords as salt:password or similar. Something like this can get a good salt substr(sha1(rand(0, time())), 10)
alex
Thank you so much for that bit of code! I have been looking for something just like that. would this work or could i get it to work with a passwords file created with htpasswd?
sunmorgus
it would appear to have the same format...it would just be down to the encryption of the passwords...
sunmorgus
@alex: I know that you can store the salt in a file. But the purpose of a password salt is that in case your database (or in the case password file) gets leaked it is harder to decrypt the hashed passwords. If you store the salt for each password in a file then what good is the salt?
MitMaro
@sunmorgus I believe the .htpassword file uses md5 with no salt
Unkwntech
@gumbo storing the salt with the encrypted password is like taping a house key to you front door, why bother?
Unkwntech
One could use a unique salt for each password, what I've done in the past is hashed the username then taken a substring from that and used it for the salt, it's always reliable (assuming no problems with the hash library) and its unique to the hash but if someone has access to the flat file of the 'db' then likely they can access your script as well and then they can see what your doing, so it won't matter
Unkwntech
If you store against each user the salt and the value of hash( password + salt ) in the file, it still shouldn't matter if the file is compromised. The password still can't be found using rainbow tables.
Tom Haigh
Ok, I actually went back and read the script a little closer and I now understand what all it is doing. This looks like a good solution, however, I have a problem. The directories that I am going to be securing contain pdf and doc files; what would stop someone from just figuring out the address to the pdf/doc file, and circumventing the authentication to download the file? could rewriting help me prevent that?
sunmorgus
@tom haigh, this is 100% true, but IMHO if an attacker has file system access your fucked already.
Unkwntech
@Unkwntech: They could read the file without system access though. If for instance your are protecting the file with .htaccess and something goes wrong and apache sends the file to the browser. Another way the contents of the file could be shown is if there was an error and error reporting was turned on and a trace was displayed containing the text file.
MitMaro
@MitMaro if that is the case then I can probably force it to show me the script that that is being used, in which case there is nothing that can be done.
Unkwntech
I have decided to implement a solution similar to this. Thank you all for the help!
sunmorgus
oh, and just fyi...each user has a uuid for a member id that I am storing...i use this uuid as my salt...
sunmorgus
A: 

According to the apache website, http://httpd.apache.org/docs/trunk/howto/htaccess.html :

In general, you should never use .htaccess files unless you don't have access to the main server configuration file. There is, for example, a prevailing misconception that user authentication should always be done in .htaccess files. This is simply not the case. You can put user authentication configurations in the main server configuration, and this is, in fact, the preferred way to do things.

Its easy to see why this is so, too. Its far preferable to have centralized control, rather than digging through EVERY SINGLE FUCKING DIRECTORY when debugging a faulty configuration.

I urge you to transfer your htaccess file config to your main configuration file ASAP, for your own good!

Joe
I'll make the assumption that since he doesn't have access to a database that he probably doesn't have root/admin access to the server to change the server config.
Unkwntech
that would be a correct assumption! and actually, I only have one directory (with several sub-directories) that I would need to lock...
sunmorgus
Two words: <Directory /dir/subdir>
Joe
+2  A: 

Have a look at Zend_Auth. It's open source, so you can sniff around to get a feel for how an authentication module should (or could) be implemented. From the doc:

Zend_Auth is concerned only with authentication and not with authorization. Authentication is loosely defined as determining whether an entity actually is what it purports to be (i.e., identification), based on some set of credentials.

karim79
I am liking the look of this...i will dig into it further, thanks for the link!
sunmorgus