Zend - The PHP Company




Security

Add Code


login.inc  

Type: application
Added by: russellhanby
Entered: 14/08/2005
Last modified: 02/11/2007
Rating: - (fewer than 3 votes)
Views: 4824
All you need is this include file and a control statement on any page you wish to authenticate users from.


<?php
//FOREWORD///////////////////////////////////////////////////////////////////////////////////////////
//***Please read considerations***
//***This script was written by Russell Hanby, a php-scriptkiddie.
//***Russell says: "Use it and modify it at your discretion.  I want to learn, so help me out.
//***  Comments? Critiques? Email me: russellhanby@yahoo.com. Thanx and enjoy."
// HOW IT WORKS:
//     The goal of login.inc was to create an authentication scheme that was as secure as my novice
//     abilities could make it, and also easy to use on any page. The core of the scheme is the token
//     object which stores several authentication variables.  These variable include a username,
//     password, timestamp, remote addr, remote hostname, and session_id.  Alone, these variable are
//     seemingly arbitrary because any one of them could be potentially forged. However, when combined
//     and compared against multiple sources,    these variables create a strong scheme with which to
//     authenticate users.
//CONTENTS:
//  FUNCTIONS:    login_check(), ssl_redirect(), login(), enc_token(), dec_token(), valid_token(), 
//      create_token(), get_key(), submitting(), form_input_check(), loggin_in(), logged_in(),
//        process_user_pass()
//    CLASSES:    token
//
//WHAT YOU NEED:
//    FILES: user_pass file, key file
//    MODULES: mcrypt support
//
//CONSIDERATIONS:
//    Encryption - the encryption used for the token is RIJNDAEL_256. The key is derived "randomly"
//      each time the enc_token() function is called by first picking a random "key coordinate" and then
//      passing this $kc to the get_key() function. This function opens the key_file and extracts a 32
//      character key starting at the $kc point in the file.  The beauty of this is that the token
//      never appears the same, the token is cookie safe, and the key_file can be changed at anytime.
//     Key File- a file containing 10,000 "random" ASCII characters in the 32 to 255 range.  This 
//       file can be created and recreated with the following code:
//      function create_key_file()
//      {
//         $path = 'c:pathtokey_file.ext';
//         if(!fopen($path, "w")) echo("file write failed");
//         else
//         {
//             $counter = 1;
//             while($counter < 10000)
//             {
//                 $chr = chr(mt_rand(33,255));
//                 fwrite($file,$chr);
//                 $counter += 1;
//             }
//             fclose($file);
//         }
//      }
//     SSL - checking for ssl and appropriately redirecting is supported. Simply uncomment the lines in
//       the login_check() function and the ssl_redirect() function.
//    SESSION - session_start() is called at the beggining of the file, so consider this when writing
//      session code outside of the file.
//     PROCESS_USER_PASS - this function does not account for the use of salt with the stored usernames
//       and passwords.  This functionality can be added by adding a $salt variable to the function.
//     LOGIN - the login_check() function is set up to display a default login form if the user is not
//       authenticated or if the user has not logged in.  You can edit this form and the way it is
//       displayed by editing both functions. Also, it may be helpful to move the login() function call
//      outside of the login_check() function, and include it in your control on your page.
//
// HOW TO USE LOGIN.INC:
//     (1) create user_pass file - storing usernames and passwords in the following format:
//       "user:passnr", where user and pass are the md5 hashs (without salt) of the valid users, and
//       "nr" is the new line delimiter.
//     (2) create key_file - use the function above to create such a file.  If you choose to use your
//       own key_file, make sure to edit the get_key() function to account for a different size of file.
//       Also, you can recreate a new key_file (for added security) at any time using this function.
//     (3) login.inc - include the file at the beggining of any page you wish to require
//       authentication.
//     (4) login_check - add control to page after include.  For example:
//         if(login_check()) { insert code if user is authenticated; }
//         else { insert code if user is not authenticated; }
//     (5) you're done!
/////////////////////////////////////////////////////////////////////////////////////////////////////

session_start();

/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : login_check;
// Function Purpose: determines status of user and //calls appropriate functions;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function login_check()
{
    if(
logged_in())
    {
        if(
valid_token())
        {
            return 
true;
        }
        else return 
false;
    }
    elseif(
logging_in())
    {
        if(
process_user_pass(md5($_POST['USER']),md5($_POST['PASS'])))
        {
            
create_token();
            unset(
$_POST['USER']);
            unset(
$_POST['PASS']);
            return 
true;
        }
        else 
        {
            
//If using ssl for login, uncomment the following if statement and
            //edit ssl_redirect function
            /*if($_SERVER['HTTPS']=="off") ssl_redirect();
            else */
login($_SERVER['PHP_SELF']);
            return 
false;
        }
    }
    else
    {
        
//If using ssl for login, uncomment the following if statement and
        //edit ssl_redirect function
        /*if($_SERVER['HTTPS']=="off") ssl_redirect();
        else */
login($_SERVER['PHP_SELF']);
        return 
false;
    }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : ssl_redirect;
// Function Purpose: redirects user to a secure //connection;
// Recieves        : nothing;
// Returns         : nothing;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function ssl_redirect()
{
    
/*$url1 = "https://";
    $url2 =  $_SERVER['SERVER_NAME'];
    $url3 = $_SERVER['PHP_SELF'];
    $url = "$url1$url2$url3";
    //either display link for redirection
        //echo("You must login over a secure connection...<BR>");
        //echo("<A HREF=$url>Click here for a secure connection</A>");
    //or use header function to redirect
        //header("location: $url");
    //or insert your own code here*/
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : login;
// Function Purpose: displays login form with provided //action, which is just PHP_SELF, unless
//                     otherwise specified;
// Recieves        : $act - action for processing login //form;
// Returns         : nothing;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function login($act)
{
$loginform "<STYLE TYPE=text/css REL=stylesheet>
.loginbox { display: block; position: relative;    height: 110px; width: 300px;
  font-family: arial; color: blue; border: solid 1px blue; text-align: center;
  padding: 8px;}
.header { text-align: center; font-size: 16; font-weight: bold; color: blue;
  background-color: #FFD700; padding: 2px; border: solid 1px blue;}
.button { width: 60px; border: solid 1px blue; color: blue; background: white;
  cursor: pointer; border: inset 1px blue; padding: 2px;}
</STYLE>
<FORM CLASS=loginbox METHOD=post ACTION=
$act>
<TABLE ALIGN=center>
<TR><TD ALIGN=center COLSPAN=2 CLASS=header>Log in...</TD></TR>
<TR><TD>User:</TD><TD><INPUT TYPE=text SIZE=25 MAXLENGTH=20 NAME=USER></TD></TR>
<TR><TD>Pass:</TD><TD><INPUT TYPE=password SIZE=25 MAXLENGTH=25 NAME=PASS></TD></TR>
<TR><TD ALIGN=center COLSPAN=2><INPUT TYPE=submit NAME=LOGIN VALUE=LOGIN CLASS=button></TD></TR>
</TABLE>
</FORM>"
;
    echo(
$loginform);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Class Name   : token;
// Class Purpose: stores variables for validation;
// Recieves     : $u - plaintext username;
//                  $p - plaintext password;
//                  $s - session id;
//                  $t - time stamp;
//                  $h - hostname of remote //user;
//                  $a - ip of remote user;
// Returns      : nothing;
// Consideration: username and password are stored //in plaintext so that they can be used for other
//                  functions if necessary;
/////////////////////////////////////////////////////////////////////////////////////////////////////
class token
{
    private 
$user;
    private 
$pass;
    private 
$sess_id;
    private 
$time_stamp;
    private 
$host;
    private 
$addr;
    
    function 
__construct($u,$p,$s,$t,$h,$a)
    {
        
$this->user $u;
        
$this->pass $p;
        
$this->sess_id $s;
        
$this->time_stamp $t;
        
$this->host $h;
        
$this->addr $a;
    }
    
    function 
user() { return $this->user; }
    function 
pass() { return $this->pass; }
    function 
time_stamp() { return $this->time_stamp; }
    function 
sess_id() { return $this->sess_id; }
    function 
host() { return $this->host; }
    function 
addr() { return $this->addr; }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : enc_token;
// Function Purpose: serializes, encrypts, and then //base64 encodes bare token object for storage;
// Recieves        : $o - token object;
// Returns         : $enc_token - encoded/encrypted //token string;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function enc_token($o)
{
    
$ser_token serialize($o);
    
$iv_size mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256MCRYPT_MODE_CBC);
    
$iv mcrypt_create_iv($iv_sizeMCRYPT_RAND);
    
$kc mt_rand(099968);
    
$_SESSION['KC'] = $kc;
    
$key get_key($kc);
    
$crypt_token mcrypt_encrypt(MCRYPT_RIJNDAEL_256$key$ser_tokenMCRYPT_MODE_CBC$iv);
    
$enc_token base64_encode($crypt_token);
    return 
$enc_token;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : dec_token;
// Function Purpose: base64 decodes, decrypts, and //then unserializes token string;
// Recieves        : $str - encoded/encrypted string;
// Returns         : $unser_token - token object;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function dec_token($str)
{
    
$dec_token base64_decode($str);
    
$iv_size mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256MCRYPT_MODE_CBC);
    
$iv mcrypt_create_iv($iv_sizeMCRYPT_RAND);
    
$kc $_SESSION['KC'];
    
$key get_key($kc);
    
$decrypt_token mcrypt_decrypt(MCRYPT_RIJNDAEL_256$key$dec_tokenMCRYPT_MODE_CBC$iv);
    
$unser_token unserialize($decrypt_token);
    return 
$unser_token;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : valid_token;
// Function Purpose: validates token against SESSION //and SERVER variables,as well as user_pass file;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function valid_token()
{
    
$enc_token $_SESSION['TOKEN'];
    
$dec_token dec_token($enc_token);
    
$sess_id session_id();
    
$timestamp $_SESSION['TIME_STAMP'];
    
$host $_SERVER['REMOTE_HOST'];
    
$addr $_SERVER['REMOTE_ADDR'];
    
$token_timestamp $dec_token->time_stamp();
    
$token_sess_id $dec_token->sess_id();
    
$token_user md5($dec_token->user());
    
$token_pass md5($dec_token->pass());
    
$token_host $dec_token->host();
    
$token_addr $dec_token->addr();
    if(
$timestamp == $token_timestamp and $sess_id == $token_sess_id and 
        
$host == $token_host and $addr == $token_addr and 
        
process_user_pass($token_user,$token_pass)==true) return true;
    else return 
false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : create_token;
// Function Purpose: creates token object, calls //enc_token, and stores token in SESSION;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function create_token()
{
    
$date getdate();
    
$_SESSION['TIME_STAMP'] = $date;
    
$sess_id session_id();
    
$user $_POST['USER'];
    
$pass $_POST['PASS'];
    
$host $_SERVER['REMOTE_HOST'];
    
$addr $_SERVER['REMOTE_ADDR'];
    
$token = new token($user,$pass,$sess_id,$date,$host,$addr);
    
$enc_token enc_token($token);
    
$_SESSION['TOKEN'] = $enc_token;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : get_key;
// Function Purpose: gets key from key_file using "key //coordinate"
// Recieves        : $kc - "key coordinate";
// Returns         : $key - key from file(upon success);
//                     false(upon failure);
/////////////////////////////////////////////////////////////////////////////////////////////////////
function get_key($kc)
{
    
//CONSIDERATION: there is no error checking for a failed read on the key_file, the function 
    //will simply return false upon failure, so make sure your key_file is being read properly, or
    //add control statement in enc/dec_token functions.
    
$path 'C:pathtokey_file.ext';
    if(!
$file fopen($path,'r'))
        return 
false;
    else
    {
        
$start $kc;
        
fseek($file,$start);
        
$key fgets($file,33);
        
fclose($file);
        return 
$key;
    }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : submitting;
// Function Purpose: determines if a user is submitting //a form;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function submitting()
{
    if(!isSet(
$_POST['USER']) or !isSet($_POST['PASS']) or !isSet($_POST['LOGIN'])) return false;
    else return 
true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : form_input_check;
// Function Purpose: ensures form input is semi-valid;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function form_input_check()
{
    
//If you wish, you may insert your own code to scrutinize form_input more thoroughly
    
if($_POST['USER'] == "" or strlen($_POST['USER']) > 20) return false;
    elseif(
$_POST['PASS'] == "" or strlen($_POST['PASS']) > 25) return false;
    else return 
true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : loggin_in;
// Function Purpose: runs functions to determine if a //user is logging in;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function logging_in()
{
    if(!
submitting()) return false;
    elseif (!
form_input_check()) return false;
    else return 
true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : logged_in;
// Function Purpose: determines if a user is logged in;
// Recieves        : nothing;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function logged_in()
{
    if(!isset(
$_SESSION['Token']) or !isset($_SESSION['TIME_STAMP']) or 
        !isset(
$_SESSION['KC'])) return false;
    else return 
true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Function Name   : process_user_pass;
// Function Purpose: validates username and password //against user_pass_file
// Recieves        : $u - md5 hash of username;
//                     $p - md5 hash of password;
// Returns         : bool;
/////////////////////////////////////////////////////////////////////////////////////////////////////
function process_user_pass($u,$p)
{
    
//CONSIDERATION: if users are not able to be //validated, make sure user_pass_file is being
    //read properly. Also, this function assumes //usernames and passwords are stored in the following
    //manner- '$u:$pnr'
    
$path 'C:pathtouser_pass_file.ext';
    if(!
$file fopen($path,"r"))
    {
        return(
false);
    }
    while(!
feof($file))
    {
        
$line fgets($file67);
        
$user_pass explode(":",$line);
        list(
$parseduser$parsedpass) = $user_pass;
        
$parsedpass trim($parsedpass);
        if(
$parseduser==$u && $parsedpass==$p)
        {
            
fclose($file);
            return(
true);
        }
    }
    
fclose($file);
    return(
false);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////

?>


Usage Example




Rate This Script





Search



This Category All Categories