RE: Re: email verificator

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



$cookie is set is 2 different places :-

$cookie = $this->db->quote($_SESSION['cookie']);
$cookie = $this->db->quote($cookie);

Rob. 

-----Original Message-----
From: php-objects@xxxxxxxxxxxxxxx [mailto:php-objects@xxxxxxxxxxxxxxx] On
Behalf Of agus susilo
Sent: 19 June 2007 17:06
To: php-objects@xxxxxxxxxxxxxxx
Subject: Re:  Re: email verificator

Hello everybody, my name is Agus. i am beginner in php programming, sorry.
just 2 the point.

to php programmer, i have some question about secure login. 
in this part, where var $cookie come from ? and where the start i could fill
this var $cookie value. 
because i was read at many times, but i did not found where the first code
begining. suddenly this var have read by some function. here the code that i
read.

i have read this article from http://www.devshed.com

In this article Martin explains how to create a secure PHP login script that
will allow safe authentication. 
Features remember-me function using cookies, validates logins on each request
to prevent session stealing.

How Does This Work

This is a short explanation why I have chosen these authentication methods.

Users with shell access to the web server can scan valid session id's if the
default /tmp directory is used  to store the session data.

The protection against this kind of attack is the IP check.

Somebody who has a site (on a shared host with you) can generate valid
session for your site.

This is why the checkSession method is used and the session id is recorded in
the database.

Somebody may sniff network traffic and catch the cookie.

The IP check should eliminate this problem too.

Preparation

You need first to decide what information to store about members, the
examples provided will assume almost nothing to make it easier to read.

I will use the PHP 4.1 super global arrays like $_SESSION, $_GET, etc. If you
want to make it work on an earlier version of PHP you will have to substitute
these with $GLOBALS['HTTP_SESSION_VARS'].

Database Schema

This is only an example bare structure suitable for online administration, if
you want to have registered members you should add more columns.

The schema is somewhat MySQL specific, I have yet to use another database
other than MySQL and PostgreSQL but if you are using PostgreSQL you can
convert the schema with the example script provided in my article Converting
a database schema from MySQL to PostgreSQL.

CREATE TABLE member (
id int NOT NULL auto_increment,
username varchar(20) NOT NULL default '', password char(32) binary NOT NULL
default '', cookie char(32) binary NOT NULL default '', session char(32)
binary NOT NULL default '', ip varchar(15) binary NOT NULL default '',
PRIMARY KEY (id), UNIQUE KEY username (username) );

The password and cookie fields are md5 hashes which are always 32 octets
long. 
Cookie is the cookie value that is sent to the user if he/she requests to be
remembered, session and ip are respectively the session id and the current IP
of the visitor.

Connecting to the Database

function &db_connect() {
require_once 'DB.php';
PEAR::setErrorHandling(PEAR_ERROR_DIE);
$db_host = 'localhost';
$db_user = 'shaggy';
$db_pass = 'password';
$db_name = 'shaggy';
$dsn = "mysql://$db_user:$db_pass@unix+$db_host/$db_name";
$db = DB::connect($dsn);
$db->setFetchMode(DB_FETCHMODE_OBJECT);
return $db;
}

This function connects to the database returning a pointer to a PEAR database
object.

Session Variables

To ease access to the current user's information we register it as session
variables but to prevent error messages and set some defaults we use the
following function.

function session_defaults() {
$_SESSION['logged'] = false;
$_SESSION['uid'] = 0;
$_SESSION['username'] = '';
$_SESSION['cookie'] = 0;
$_SESSION['remember'] = false;
}

... with a check like:

if (!isset($_SESSION['uid']) ) {
session_defaults();
}

to set the defaults. Of course session_start must be called before that.

To the Core of the Script

To allow easier integration with other scripts and make things more modular
the core script is an object with very simple interface.

class User {
var $db = null; // PEAR::DB pointer
var $failed = false; // failed login attempt var $date; // current date GMT
var $id = 0; // the current user's id function User(&$db) { $this->db = $db;
$this->date = $GLOBALS['date']; i f ($_SESSION['logged']) {
$this->_checkSession(); } elseif ( isset($_COOKIE['mtwebLogin']) ) {
$this->_checkRemembered($_COOKIE['mtwebLogin']);
}
}

This is the class definition and the constructor of the object. OK it's not
perfectly modular but a date isn't much of a problem. It is invoked like:

$date = gmdate("'Y-m-d'");
$db = db_connect();
$user = new User($db);

Now to clear the code purpose, we check if the user is logged in. If he/she
is then we check the session (remember it is a secure script), if not and a
cookie named just for example mtwebLogin is checked - this is to let
remembered visitors be recognized.

Logging in Users

To allow users to login you should build a web form, after validation of the
form you can check if the user credentials are right with
$user->_checkLogin('username', 'password', remember). 
Username and password should not be constants of course, remember is a
boolean flag which if set will send a cookie to the visitor to allow later
automatic logins.

function _checkLogin($username, $password, $remember) { $username =
$this->db->quote($username); $password = $this->db->quote(md5($password));
$sql = "SELECT * FROM member WHERE " .
"username = $username AND " .
"password = $password";
$result = $this->db->getRow($sql);
if ( is_object($result) ) {
$this->_setSession($result, $remember);
return true;
} else {
$this->failed = true;
$this->_logout();
return false;
}
}

The function definition should be placed inside the User class definition as
all code that follows. 
The function uses PEAR::DB's quote method to ensure that data that will be
passed to the database is safely escaped. 
I've used PHP's md5 function rather than MySQL's because other databases may
not have that.

The WHERE statement is optimized (the order of checks) because username is
defined as UNIQUE.

No checks for a DB_Error object are needed because of the default error mode
set above. If there is a match in the database $result will be an object, so
set our session variables and return true (successful login). 
Otherwise set the failed property to true (checked to decide whether to
display a login failed page or not) and do a logout of the visitor.

The logout method just executes session_defaults().

Setting the Session

function _setSession(&$values, $remember, $init = true) { $this->id =
$values->id; $_SESSION['uid'] = $this->id; $_SESSION['username'] =
htmlspecialchars($values->username);
$_SESSION['cookie'] = $values->cookie;
$_SESSION['logged'] = true;
if ($remember) {
$this->updateCookie($values->cookie, true); } if ($init) { $session =
$this->db->quote(session_id()); $ip =
$this->db->quote($_SERVER['REMOTE_ADDR']);

$sql = "UPDATE member SET session = $session, ip = $ip WHERE " .
"id = $this->id";
$this->db->query($sql);
}
}

This method sets the session variables and if requested sends the cookie for
a persistent login, there is also a parameter which determines if this is an
initial login (via the login form/via cookies) or a subsequent session check.

Persistent Logins

If the visitor requested a cookie will be send to allow skipping the login
procedure on each visit to the site. 
The following two methods are used to handle this situation.

function updateCookie($cookie, $save) {
$_SESSION['cookie'] = $cookie;
if ($save) {
$cookie = serialize(array($_SESSION['username'], $cookie) );
set_cookie('mtwebLogin', $cookie, time() + 31104000, '/directory/'); } }

Checking Persistent Login Credentials

If the user has chosen to let the script remember him/her then a cookie is
saved, which is checked via the following method.

function _checkRemembered($cookie) {
list($username, $cookie) = @unserialize($cookie); if (!$username or !$cookie)
return; $username = $this->db->quote($username); $cookie =
$this->db->quote($cookie); $sql = "SELECT * FROM member WHERE " .
"(username = $username) AND (cookie = $cookie)"; $result =
$this->db->getRow($sql); if (is_object($result) ) {
$this->_setSession($result, true); } }

This function should not trigger any error messages at all. To make things
more secure a cookie value is saved in the cookie not the user password. This
way one can request a password for areas which require even higher security.

Ensuring Valid Session Data

function _checkSession() {
$username = $this->db->quote($_SESSION['username']);
$cookie = $this->db->quote($_SESSION['cookie']);
$session = $this->db->quote(session_id()); $ip =
$this->db->quote($_SERVER['REMOTE_ADDR']);
$sql = "SELECT * FROM member WHERE " .
"(username = $username) AND (cookie = $cookie) AND " .
"(session = $session) AND (ip = $ip)";
$result = $this->db->getRow($sql);
if (is_object($result) ) {
$this->_setSession($result, false, false); } else { $this->_logout(); } }

So this is the final part, we check if the cookie saved in the session is
right, the session id and the IP address of the visitor. The call to
setSession is with a parameter to let it know that this is not the first
login to the system and thus not update the IP and session id which would be
useless anyway.

DISCLAIMER: The content provided in this article is not warranted or
guaranteed by Developer Shed, Inc. 
The content provided is intended for entertainment and/or educational
purposes in order to introduce to the reader key ideas, concepts, and/or
product reviews. As such it is incumbent upon the reader to employ real-world
tactics for security and implementation of best practices. We are not liable
for any negative consequences that may result from implementing any
information covered in our articles or tutorials. 
If this is a hardware review, it is not recommended to open and/or modify
your hardware.



       
---------------------------------
Looking for a deal? Find great prices on flights and hotels with Yahoo!
FareChase.

[Non-text portions of this message have been removed]



PHP Data object relational mapping generator http://www.metastorage.net/
Yahoo! Groups Links




***********************************************************************************
Any opinions expressed in email are those of the individual and not necessarily those of the company. This email and any files transmitted with it are confidential and solely for the use of the intended recipient 
or entity to who they are addressed. It may contain material protected by attorney-client privilege. If you are not the intended recipient, or a person responsible for delivering to the intended recipient, be advised that you have received this email in error and that any use is strictly prohibited.

Random House Group + 44 (0) 20 7840 8400
http://www.randomhouse.co.uk
http://www.booksattransworld.co.uk 
http://www.kidsatrandomhouse.co.uk
Generic email address - enquiries@xxxxxxxxxxxxxxxxx

Name & Registered Office:
THE RANDOM HOUSE GROUP LIMITED
20 VAUXHALL BRIDGE ROAD
LONDON
SW1V 2SA
Random House Group Ltd is registered in the United Kingdom with company No. 00954009, VAT number 102838980
***********************************************************************************


[Index of Archives]     [PHP Home]     [PHP Users]     [PHP Soap]     [Kernel Newbies]     [Yosemite]     [Yosemite Campsites]

  Powered by Linux