|
Posted by Steve on 02/14/07 14:58
"weetat" <weetat.yeo@gmail.com> wrote in message
news:1171446164.007337.72340@a34g2000cwb.googlegroups.com...
| Hi all ,
|
| I have question regarding user authentication in php.
| Anybody have any ideas how to verify user authentication to activate
| account?
|
| I have requirement from my customer that when the user registered in
| the page, it want to sent email to the particular user with the link
| to activate the account.
| The user is not activate until he or she activate the account by click
| the link in email.
|
| Any one have suggestion is much appreciated ?
here's something i've used in the past. it is a security script included in
any page that should only be accessed by authorized users. there are
improvements to be made, but it should help you get a start. sorry for the
text wrapping.
$site is a class that defines the application's configuration. it is
included in a script that is used for every page. in that script
(site.cfg.php), you'll see this code:
==========
$site->lastSecurityCode = $_SESSION['securityCode'];
$alphabet = '2347ACEFHJKLMNPRTWXYZ'; // removed 0, 1, I,
O, Q, D, 8, 9, B, 5, S, 6, G, U, V - look too similar
$alphabetLength = strlen($alphabet) - 1;
$site->securityCode = '';
for ($i = 0; $i < 6; $i++)
{
$site->securityCode .= $alphabet[mt_rand(0, $alphabetLength)];
}
$_SESSION['securityCode'] = strtoupper($site->securityCode);
if (!isset($site->lastSecurityCode)){ $site->lastSecurityCode =
$_SESSION['securityCode']; }
===========
that sets the security code. that code is displayed in an image beneath a
login form and is verified when the user supplied code matches the
$site->securityCode. the database calls are from an abstracted, static class
called db. this implementation of db is working with mysql.
tracking can be done with the isp class...it contains:
============
class isp
{
public $address = '';
public $city = '';
public $clientIp = '';
public $country = '';
public $email = '';
public $name = '';
public $phone = '';
public $state = '';
public $zip = '';
private function __clone(){}
public function __construct($ip = '')
{
if (!$ip){ $ip = $_SERVER['REMOTE_ADDR']; }
$this->clientIp = $ip;
$query =
file_get_contents("http://ws.arin.net/cgi-bin/whois.pl?queryinput=$ip");
if(strstr($query, "No match")){ return; }
$this->name = $this->getSegment('OrgName:', $query);
if ($isp->isp == '')
{
$href = preg_match('/HREF="([^"]*)"/', $query, $uri);
$href = 'http://ws.arin.net' . $uri[1];
$query = file_get_contents($href);
}
$this->address = strtoupper($this->getSegment('Address:' ,
$query));
$this->city = strtoupper($this->getSegment('City:' ,
$query));
$this->country = strtoupper($this->getSegment('Country:' ,
$query));
$this->email = strtolower($this->getSegment('OrgAbuseEmail:' ,
$query));
$this->name = strtoupper($this->getSegment('OrgName:' ,
$query));
$this->phone = strtoupper($this->getSegment('OrgAbusePhone:' ,
$query));
$this->state = strtoupper($this->getSegment('StateProv:' ,
$query));
$this->zip = strtoupper($this->getSegment('PostalCode:' ,
$query));
}
private function getSegment($segment, $source)
{
$pattern = '/' . $segment . '([^\n]*)\n/i';
$segment = preg_match($pattern, $source, $matches);
$segment = preg_replace('/<[^>]*>/', '', $matches[1]);
return $segment;
}
}
============
that way, if you decide, you can store failures to detect hack attempts and
get a huge start on tracking the offender's isp. finally, there is an
abbreviated email static class i use in lieu of php's and pear's mail
functionality. it looks like:
===================
class email
{
static function send(
$to ,
$from ,
$cc = '' ,
$bcc = '' ,
$subject ,
$text = '' ,
$html = '' ,
$companyName = '' ,
$logo = null ,
$dropDirectory = '' ,
$exec = '' ,
$execOptions = ''
)
{
$messageHtml = $html;
$html = '
<html>
<style>
body
{
background-color : white;
color : black;
font-family : verdana, tahoma, arial, times new
roman, sans-serif;
font-size : 8pt;
margin : 0px;
text-align : left;
}
</style>
<body>
';
if (isset($logo))
{
$image = file_get_contents($logo);
$image = chunk_split(base64_encode($image));
$html .= '
<img alt="' . $companyName . '" border="0px"
src="cid:logo" style="float:right;">
<br>
<br>
<br>
<br clear="all">
';
}
if ($messageHtml == ''){ $messageHtml = '<html><body>' . $text; }
$html .= $messageHtml . '</body></html>';
if ($text == ''){ $text = $html; }
$boundry = '----=' . md5(uniqid(rand()));
$related = '----=' . md5(uniqid(rand()));
$mail = "MIME-Version: 1.0\r\n";
$mail .= "TO: " . $to . "\r\n";
$mail .= "FROM: " . $from . "\r\n";
$mail .= "CC: " . $cc . "\r\n";
$mail .= "BCC: " . $bcc . "\r\n";
$mail .= "Subject: " . $subject . "\r\n";
$mail .= "Content-Type: multipart/related;
boundary=\"$related\"\r\n\r\n\r\n";
$mail .= "--$related\r\n";
$mail .= "Content-Type: multipart/alternative;
boundary=\"$boundry\"\r\n\r\n\r\n";
$mail .= "--$boundry\r\n";
$mail .= "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n";
$mail .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$mail .= $text . "\r\n\r\n";
$mail .= "--$boundry\r\n";
$mail .= "Content-Type: text/html; charset=\"iso-8859-1\"\r\n";
$mail .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$mail .= $html . "\r\n\r\n";
$mail .= "--$boundry--\r\n\r\n";
$mail .= "--$related\r\n";
$mail .= "Content-Type: image/jpeg\r\n";
$mail .= "Content-ID: logo\r\n";
$mail .= "Content-Disposition: attachment;
filename=\"logo.jpg\"\r\n";
$mail .= "Content-Transfer-Encoding: base64\r\n\r\n";
$mail .= $image . "\r\n\r\n";
$mail .= "--$related--\r\n\r\n";
$mail .= "-- End --\r\n";
$fileName = $dropDirectory . strtoupper(md5(uniqid(rand()))) . '.eml';
file_put_contents($fileName, $mail);
if (!$exec){ return $mail; }
exec($exec . $fileName . $execOptions);
@unlink($fileName);
return $mail;
}
}
==================
notice how it is used in the main security script below. if you are using
windows and have iis smtp running, just change the drop directory to
c:/inetpub/mailroot/pickup/ and remove the exec and execOptions args used
below.
anyway, all that to say that this is the main script...hope this gives you
an idea of how some people do it:
======================
<?
if (!isset($pageTitle)){ $pageTitle = 'Authorization Required'; }
require_once 'relative.path.php';
require_once $relativePath . 'site.cfg.php';
$_SESSION['securityAttempts'] = $_SESSION['securityAttempts'] == '' ? 0
: $_SESSION['securityAttempts'];
$securityCode = isset($_POST['securityCode']) ?
$_POST['securityCode'] : '';
$logIn = isset($_POST['logIn']);
$forgotPassword = isset($_REQUEST['forgotPassword']);
$passport = isset($_REQUEST['passport']) ?
$_REQUEST['passport'] : '';
$refresh = isset($_POST['refresh']);
$userPassword = isset($_POST['userPassword']) ?
$_POST['userPassword'] : $_SESSION['userPassword'];
$userName = isset($_REQUEST['userName']) ?
$_REQUEST['userName'] : $_SESSION['userName'];
$userVerified = false;
$sql = "
SELECT CONCAT(
FirstName ,
' ' ,
LastName
) Description ,
Password ,
UserName ,
Email ,
Expired ,
Passport
FROM people
WHERE UserName = '" . $userName . "'
OR Email = '" . $userName . "'
";
unset($records);
$records = db::execute($sql);
$accessedBy = $userName;
$userName = $records[0]['USERNAME'];
$storedPassport = $records[0]['PASSPORT'];
$storedPassword = $records[0]['PASSWORD'];
$chancesLeft = 2 - $_SESSION['securityAttempts'];
$securityCode = strtoupper($securityCode);
$logInMessage = 'Please Log In';
$isSecure = count($records) &&
$storedPassword == $userPassword &&
!$logOut &&
($logIn ? $securityCode == $site->lastSecurityCode :
!$logOut);
$passwordExpired = $records[0]['EXPIRED'];
$userEmail = $records[0]['EMAIL'];
$userFullName = $records[0]['DESCRIPTION'];
$profile = $site->uri . 'my.account.php';
$securityHeader = $sessionHeader;
$securityHeader .= " <div class=\"body\" style=\"background-image:url("
.. $site->imagesDirectory . 'background.jpg' . ");\"> \r\n";
$securityHeader .= " <div style=\"background:white no-repeat url(" .
$site->imagesDirectory . 'header.jpg' . "); height:100px; margin-left:20px;
margin-right:20px; padding-top:100px; width:790px;\">\r\n";
$securityHeader .= " <!----- end page header -----!>
\r\n";
$securityHeader .= " <div class=\"pageContent\">
\r\n";
$securityHeader .= " <!----- start page content -----!>
\r\n";
$securityHeader .= "
\r\n\r\n";
$securityFooter = "
\r\n\r\n";
$securityFooter .= " <!----- end page content -----!>
\r\n";
$securityFooter .= " <!----- start page footer -----!>
\r\n";
$securityFooter .= " <br clear=\"all\">
\r\n";
$securityFooter .= " <div class=\"footer\"
style=\"background-image:url(" . $site->imagesDirectory . 'border.jpg' . ");
width:790px;\"> \r\n";
$securityFooter .= " <span style=\"color:gray; float:left;
padding-top:15px;\">© " . date('Y') . " My Company, LTD.</span> \r\n";
$securityFooter .= " </div>
\r\n";
$securityFooter .= " <!----- end page footer -----!>
\r\n";
$securityFooter .= " </div>
\r\n";
$securityFooter .= " </div>
\r\n";
$securityFooter .= " </div>
\r\n";
$securityFooter .= " </body>
\r\n";
$securityFooter .= "</html>
\r\n";
function handleError($title, $description, $track = true)
{
global $site;
global $securityHeader;
global $securityFooter;
global $accessedBy;
$isp = new isp();
$html[] = '
<br>
<br>
<div style="color:#660000; font-size:10pt; font-weight:bold;">
' . $title . '
</div>
<hr style="background-color:#660000; color:#660000;">
<br>
<br>
';
$html[] = $description . '. If this is a mistake, please contact the
<a href="mailto:' . $site->adminEmail . '" title="Web Administrator">Web
Administrator</a> for
further assistance. Continued attempts from your IP address to login will
be seen as an effort to
compromise this site\'s security - which we simply will not tolerate.
<br>
<br>
<hr>
<br>
';
$html[] = '
<table style="width:400px;">
<tr>
<td style="font-weight:bold">IP</td>
<td>' . $isp->clientIp . '</td>
</tr>
<tr>
<td style="font-weight:bold">ISP</td>
<td>' . $isp->name . '</td>
</tr>
<tr>
<td style="font-weight:bold">Address</td>
<td>' . $isp->address . '</td>
</tr>
<tr>
<td style="font-weight:bold">City</td>
<td>' . $isp->city . '</td>
</tr>
<tr>
<td style="font-weight:bold">State / Province</td>
<td>' . $isp->state . '</td>
</tr>
<tr>
<td style="font-weight:bold">Postal Code</td>
<td>' . $isp->zip . '</td>
</tr>
<tr>
<td style="font-weight:bold">Country</td>
<td>' . $isp->country . '</td>
</tr>
<tr>
<td style="font-weight:bold">Phone</td>
<td>' . $isp->phone . '</td>
</tr>
<tr>
<td style="font-weight:bold">Email</td>
<td>' . $isp->email . '</td>
</tr>
</table>
';
echo $securityHeader;
echo implode('', $html);
echo $securityFooter;
if (!$track){ return; }
$html[1] = '
' . $accessedBy . ' attempted to gain access to the system but has failed.
The following
information was collected showing the connection details. This information
can be used
to track the source of the possible intrusion. This information does not
definitively point
to ' . $accessedBy . ' being the culprit. That account is merely being
used as a way into
the system. Either way, ' . $accessedBy . ' should be contacted to see if
help is needed and,
to verify that no one else is trying to compromise the system through that
account.
<br>
<br>
Please retain this information for your records so that unauthorized
access attempts can
be discerned from simple user error.
<br>
<br>
Thank you.
<br>
<br>
<hr style="background-color:#660000; color:#660000;">
<br>
';
$style = '
<style>
table
{
border-collapse : collapse;
border-padding : 2px;
border-width : 0px;
border-spacing : 0px;
width : 400px;
}
td
{
background-color : white;
color : black;
font-family : verdana, tahoma, arial, sans-serif;
font-size : 8pt;
margin : 0px;
padding : 0px;
padding-left : 2px;
padding-right : 2px;
spacing : 0px;
text-align : right;
vertical-align : middle;
}
</style>
';
$html = $style . implode('', $html);
email::send(
$site->adminEmail ,
$site->adminEmail ,
'' ,
'' ,
$site->title . ' - Security Alert' ,
'' ,
$html ,
$site->title ,
$site->rootDirectory . 'images/email.logo.jpg' ,
$site->mailDropDirectory ,
'/usr/sbin/sendmail -ti < '
);
}
if ($isSecure)
{
$userVerified = true;
$_SESSION['securityAttempts'] = 0;
$_SESSION['userName'] = $userName;
$_SESSION['userPassword'] = $userPassword;
$_SESSION['userFullName'] = $userFullName;
if ($passwordExpired)
{
if ($site->currentPage != basename($profile))
{
header('location:' . $profile . '?userName=' . urlencode($userName) .
'&passport=' . urlencode($passport));
exit;
}
}
} else {
$_SESSION['userName'] = '';
$_SESSION['userPassword'] = '';
$_SESSION['userFullName'] = '';
require_once $site->classDirectory . 'isp.class.php';
require_once $site->classDirectory . 'email.class.php';
if ($chancesLeft < 1)
{
$title = 'Unauthorized Access Not Permitted';
$description = 'Your IP address and all related internet traffic is
being monitored and logged';
handleError($title, $description);
exit;
}
if ($forgotPassword && $userName){ $passwordExpired = true; }
if ($logIn || ($forgotPassword && !$userName))
{
$_SESSION['securityAttempts']++;
$isSecurityCode = $securityCode == $site->lastSecurityCode &&
!($forgotPassword && !$userName);
$logInMessage = '<font style="color:#990000;">';
$logInMessage .= $isSecurityCode ? ' Invalid Security Code' : '
Invalid User Name/Password';
$logInMessage .= ' - You have ' . $chancesLeft . ' chance' .
($chancesLeft == 1 ? '' : 's') . ' left';
$logInMessage .= '</font>';
}
if (($refresh || $logIn || !$isSecure) && !$passwordExpired)
{
echo $sessionHeader;
?>
<script type="text/javascript">
function forgotPassword()
{
var userName = records.userName.value;
if (!userName)
{
var errorMessage = document.getElementById('errorMessage');
errorMessage.style.position = 'absolute';
errorMessage.style.display = '';
records.userName.focus();
return false;
}
window.location.href = '<?= $site->uri ?>?userName=' +
records.userName.value + '&forgotPassword';
return false;
}
</script>
<div class="logIn" style="background-image:url(<?= $site->imagesDirectory .
'login.jpg' ?>);">
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="post" name="records">
<table style="border:solid 1px black; float:right; width:225px;">
<tr>
<td colspan="2" style="background-color:lightsteelblue;
border-bottom:solid 1px white; font-weight:bold; padding-bottom:10px;">
<?= $logInMessage ?>
</td>
</tr>
<tr><td colspan="2"
style="background-color:lightsteelblue;"> </td></tr>
<tr>
<td style="background-color:lightsteelblue; text-align:right;"><span
class="label" style="width:75px;">User Name</span></td>
<td style="background-color:lightsteelblue; text-align:right;">
<input class="value" name="userName" style="width:125px;"
type="text" autocomplete="off">
</td>
</tr>
<tr>
<td style="background-color:lightsteelblue; text-align:right;"><span
class="label" style="width:75px;">Password</span></td>
<td style="background-color:lightsteelblue; text-align:right;">
<input class="value" name="userPassword" style="width:125px;"
type="password" autocomplete="off">
</td>
</tr>
<tr>
<td style="background-color:lightsteelblue; text-align:right;"><span
class="label" style="width:75px;">Security Code</span></td>
<td style="background-color:lightsteelblue; text-align:right;">
<input class="value" name="securityCode" style="width:125px;"
type="text" autocomplete="off" style="text-transform:uppercase;">
</td>
</tr>
<tr><td colspan="2"
style="background-color:lightsteelblue;"> </td></tr>
<tr>
<td colspan="2" style="background-color:lightsteelblue;
padding-right:5px; text-align:right;">
<img src="<?= $site->uri ?>get.security.image.php">
</td>
</tr>
<tr><td colspan="2"
style="background-color:lightsteelblue;"> </td></tr>
<tr>
<td colspan="2" style="background-color:lightsteelblue;
text-align:center;">
<input
name="logIn"
style="background-color:lightsteelblue; color:black;
font-family:verdana, tahoma, arial, 'times new roman', sans-serif;
font-weight:bold; margin:1px; width:125px;"
type="submit"
value="Log In ▷"
>
</td>
</tr>
<tr><td colspan="2"
style="background-color:lightsteelblue;"> </td></tr>
<tr>
<td colspan="2" style="background-color:lightsteelblue;
text-align:left;">
<div style="text-align:center;">
<a href="Forgot Password" onclick="forgotPassword(); return
false;">Forgot Password</a>
</div>
<div
id="errorMessage"
style="background-color:#EEEEEE; border:1px solid black;
color:black; display:none; font-size:8pt; margin-top:10px; padding:10px;
text-align:left;"
>
Please enter your user name or email address in the USER NAME
field, then click this link again.
<br>
<br>
Thank you.
</div>
</td>
</tr>
<tr><td colspan="2"
style="background-color:lightsteelblue;"> </td></tr>
</table>
</form>
</div>
<script language="javascript">
records.userName.focus();
</script>
<?
echo $sessionFooter;
exit;
}
if ($passwordExpired)
{
if ($passport)
{
if ($site->currentPage != basename($profile))
{
header('location:' . $profile . '?userName=' . urlencode($userName)
.. '&passport=' . urlencode($passport));
exit;
}
}
if($passport && $passport != $storedPassport)
{
$title = 'Invalid Passport';
$description = 'The Passport you have provided is not valid';
handleError($title, $description);
exit;
}
if(!$passport && $storedPassport)
{
$title = 'Passport Required';
$description = 'You have not logged on with your full credentials. In
order to continue, you must provide a valid Passport';
handleError($title, $description, false);
exit;
}
if (!$storedPassport)
{
$passport = strtoupper(md5(uniqid(rand())));
$sql = "
UPDATE people
SET Expired = '1',
Passport = '" . db::prepare($passport) . "'
WHERE UserName = '" . $userName . "'
";
db::execute($sql);
$link = $site->uri . '?userName=' . urlencode($userName) .
'&passport=' . urlencode($passport);
$html = '
<div style="width:\'80%\';">
<font style="font-size:\'' . $sessionFonts['SMALL'] .
'\';">
<big><b>RESET PASSWORD REQUEST</b></big>
<br>
<br>
Your account password has expired. You are receiving
this email because you, or someone else,
has tried to access your account ( ' . $userName .
' ) without updating the password for the account.
Please notify us immediately if you were not the
person trying to log into your account. Otherwise, you
may follow the instructions below to reset your
password.
<br>
<br>
Either click the following link, or copy and paste
it into your browser.
<br>
<br>
<a href="' . $link . '">' . $link . '</a>
<br>
<br>
This will allow you to set a new password for your
account.
</font>
</div>
';
email::send(
$userEmail ,
$site->adminEmail ,
'' ,
'' ,
$site->title . ' - Reset Password Request' ,
'' ,
$html ,
$site->title ,
$site->rootDirectory . 'images/email.logo.jpg' ,
$site->mailDropDirectory ,
'/usr/sbin/sendmail -ti < '
);
echo $securityHeader;
?>
<br>
<div class="bullet" style="background:white no-repeat url('<?=
$site->imagesDirectory ?>bullet.jpg'); color:black; font-size:12pt;
height:50px; padding-top:8px; padding-left:50px;">
<?= $pageTitle ?>
</div>
<hr>
<br>
<div style="color:#660000; font-size:10pt; font-weight:bold;">
PASSWORD EXPIRED - RESET PASSWORD REQUEST SENT
</div>
<hr style="background-color:#660000; color:#660000;">
<br>
<br>
An email has been sent to the address associated with this account. In this
email, there will be a hyperlink that will
enable this account's password to be reset. This process is begun by either
clicking the hyperlink, or by copying and
pasting it into a web browser. In the resulting page, the user should click
"Save" in order to set the password.
<br>
<br>
The email just sent will contain these instructions as well. There will also
be an email address for this site's
<a href="mailto:<?= $site->adminEmail ?>" title="Web Administrator">Web
Administrator</a>. Use that email address
if further instructions or clarification is needed.
<br>
<br>
<div style="color:#660000; font-size:10pt; font-weight:bold;">
Thank You.
</div>
<br>
<br>
<?
echo $securityFooter;
$_SESSION['securityAttempts'] = 0;
exit;
}
}
}
?>
[Back to original message]
|