Jump to content

database advanced Authentification scheme


TheProgrammer

Recommended Posts

Hello people,
I've been working with php for a long time, many times with quite advanced stuff but never needed, got the chance or the time to implement a more complex and secure authentification method for a site's private section for example. What i used until now was something like this (the main ideea not the actual implementation):
- i kept the username and the password in a mysql database (the password  hashed)
- i verified the authentification like this (some parts are not real code, only the ideea, but that's what i'm looking for, the main ideea)
[code]
$auth = false;

if( isset( $_POST['username']) && isset($_POST['password']) )
{
  $u = [i]get_user_from_database[/i]
  $p = [i]get_password_from_database[/i]
  if( $u == htmlentities(trim($_POST['username'])) && $p == MD5(MD5(MD5(htmlentities(trim($_POST['password']))))))
  {
    $auth = true;
    $_SESSION['mysite_username'] = $u;
    $_SESSION['mysite_password'] = $p;
  }
}
else if( isset( $_SESSION['mysite_username']) && isset($_SESSION['mysite_password']) )
{
  if( $u == $_SESSION['mysite_username'] && $p == $_SESSION['mysite_username'] )
      $auth = true;
}

if($auth)
{
  //the page content
}
[/code]
Well I know it's quite primitive, and the fact that i save the password in session (even hashed), is at least fishy, but never needed something more secure until now.
So..can you give me a pice of advice? Or some links? Or anything that can help. You can hit me with some more advanced stuff too. I will understand  :). The documentation or samples I found on net ar quite simillar or even worse  :)
Thank you very much!
Link to comment
Share on other sites

The way i do it is whenever a user logs in, there ip address and session number (as its unique each time) are recorded against there user name in an mysql table.  Then whenever they try to access a 'private area' i run a function that checks there current ip address and session number against the one in the table. It does this by checking what these should be for the user_name specified. If they mach there aloud in, if not then they are redirected. (i do this by having the function return a 'true' or 'false' value).  The table in the database is refreshed everytime they log in.

Code for this is very simple.  The only problem i see with this is having to store your database details in a standard file.

Hope this makes sence.  Shout if not!

Link to comment
Share on other sites

well, i understand your method but..what do you do with users with the same ip? for example, if i woudnd pay an aditional fee, my network provided woldnt give me a real ip adress, but a private one (10.x.x.x or 192.128.x.x), so me and probably 100 guys would have the gateways ip for someone outside our network. What happens if they acces the page about the same time. We would all be authentificated with only one of us entering the password.
Link to comment
Share on other sites

thats the resion for using the session number as well.  The session number is unique to every web broser, and will change every time you close it and open it again.  There for you can have as many people as you like on one IP address (as this will genuraly be the outside one), but the session number will always be diffrent.  Give me a sec and ill see if i can find my code to post.
Link to comment
Share on other sites

ok, have posted the 'check' code i use below.  Try this first though.

[code]<?php

session_start();

echo session_id();

?>[/code]

If you run the script.  Quit your browser and run it again you will see that the number changes every time you do this.  The code below criticaly requires the ip address AND session id to be the same.  The ip address is not realy very important i just like to know where my users are!

[code]function check_client_cridentials($uid)
{

global $pg_connection;

session_start();

$ip=$_SERVER['REMOTE_ADDR'];

$query = "SELECT ip_address,session_id FROM authenticated_users_credentials WHERE user_id = '".$uid."'";
$result = pg_query($pg_connection, $query);
$data = pg_fetch_array($result);

       //CHECK IP ADDRESS
       if ( $data["ip_address"] == $ip )
               {
               $test1 = 1;
               }
       else
               {
               $test1 = 0;
               }


       //IF FIRST TEST IS PASSED CHECK AGAINST SESSION
       if ( $data["session_id"] == session_id() )
               {
               $test2 = 1;
               }
       else
               {
               $test2 = 0;
               }

       //RETURN WETHER CRIDENTIALS CHECKED OUT OR NOT
       if ( $test1+$test2 == 2 )
               {
               return "pass";
               }
       else
               {
               return "fail";
               }

}


if ( check_client_cridentials('13') == 'pass' )
{  
//CRIDDENTIALS CHECK OUT, LET THEM INTO PRIVATE AREA                                                                                            
echo "Bingo";
}
else
{
//CRIDDENTIALS FAILD, DO NOT ALLOW INTO PRIVAT AREA
echo "nhaaa";
}
[/code]


Hope this helps.  Sorry its two posts!
Link to comment
Share on other sites

TheProgrammer: I think the main issue, as you mentioned, is that you're obtaining security through obscurity. Although this is the done thing by some major companies <cough>microsoft</cough> it's main weakness is that the system is only secure as long as the sensitive information stays hidden (like the username in your examples). So, the goal is to somehow use information that stays secure even if it is found.

One easy method to make your logins secure, is to store the identity of the user not with a username/password, but with some other value that uniquely relates to their login, but without revealing their identity.

For example, after a user has logged in you would generate a cookie with a unique serial number (probably an MD5 hash based on the time). You would store this in your database, and next time the user initiates a request you read the hash back from the value stored in the cookie. If the value from the client's cookie matches the value in your database, you know the user was authenticated and the action is allowed. Then, you mark this hash as having been used and issues a new hash which overwrites the client's cookie and is stored for the next transaction. The point is that each hash can only be used once. If a hacker steals a hash, they only get to run the action that the user would have run anyway, but the user's password is never revealed. Of course you could also store this hash in a session instead.

The other thing to consider is the actual mechanism used to transfer the user's authentication data from the browser to your server. The HTTP protocol supports two different authentication mechanisms, which are described in RFC-2617 http://www.ietf.org/rfc/rfc2617.txt

By using the built in mechanisms, you can effectively bypass the need for sessions or cookies, and even avoid sending the username or password over the network. Perhaps the best place to start with this by reading the "HTTP authentication with PHP" chapter in the PHP documentation [url=http://www.php.net/manual/en/features.http-auth.php]http://www.php.net/manual/en/features.http-auth.php[/url]

Here is a sample code fragment  for handling the basics of authentication. Note, this script is not complete as it does not include the mechanics for a database connection or error handling.

[code]

/**
* @author Luke Van In 2006
*
* @class auth Class for providing HTTP compliant user authentication
*
*/
class auth
{

var $authenticated;
var $auth;





//
function authenticate()
{

// deny access if no username/password was entered
if ( (!$_SERVER['PHP_AUTH_USER']) || (!$_SERVER['PHP_AUTH_PW']) )
{
$this->deny($p);
return false;
}


// query the database for a record matching the entered username and password
$sql = "
SELECT
*
FROM
auth
WHERE
username = '" . mysql_escape_string($_SERVER['PHP_AUTH_USER']) . "'
AND
password = '" . mysql_escape_string($_SERVER['PHP_AUTH_PW']) . "'
LIMIT
0,1 ";

$r = mysql_query($sql);

$result = mysql_fetch_assoc($r);


// allow access if matching username / password was found
if (count($result) == 1)
{
$this->allow($result[0]);
return true;
}

// othrwise deny access
$this->deny();
return false;
}



//
function unauthenticate()
{
$this->deny();
}



//
function allow($auth)
{

$this->authenticated = true;
$this->auth = $auth;

print('Authentication successful. ' . print_r($auth, true));
}



//
function deny()
{
// popup a login prompt in the browser's window
header('WWW-Authenticate: Basic realm="My Realm"');
header("HTTP/1.0 401 Unauthorized");

$this->http_response(HTTP_ERROR_UNAUTHORIZED);

//
print('Authentication denied. ' . print_r($auth, true));
}

}


?>
[/code]

And an example usage of the class:

[code]
$auth = new auth();
$auth->authenticate();

if ($auth->authenticated)
print("signed in :)");
else
print("authentication failed :(");

[/code]

... and to provide a "Sign Out" feature:

[code]
$auth = new auth();
$auth->unauthenticate();
[/code]

The RFC goes even further to provide a more secure form of authentication over HTTP using a digest string, which circumvents the need to transfer the username or password over the network.

Adding SSL on top of HTTP digest authentication would provide a very secure authentication mechanism.

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.