Tải bản đầy đủ (.pdf) (10 trang)

Phát triển web với PHP và MySQL - p 34 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (538.05 KB, 10 trang )

their customers’ details when they make their first order. This means that a customer is not
required to type her details every time.
Having asked for and received information from your visitor, you need a way to associate the
information with the same user the next time she visits. If you are willing to make the assump-
tion that only one person visits your site from a particular account on a particular machine and
that each visitor only uses one machine, you could store a cookie on the user’s machine to
identify the user. This is certainly not true for all users—frequently, many people share a com-
puter, and many people use more than one computer. At least some of the time, you will need
to ask a visitor who she is again. In addition to asking who a user is, you will also need to ask
a user to provide some level of proof that she is who she claims to be.
As discussed in Chapter 13, “E-commerce Security Issues,” asking a user to prove her identity
is called authentication. The usual method of authentication used on Web sites is asking visi-
tors to provide a unique login name and a password. Authentication is usually used to allow or
disallow access to particular pages or resources, but can be optional, or used for other purposes
such as personalization.
Implementing Access Control
Simple access control is not difficult to implement. The code shown in Listing 14.1 delivers
one of three possible outputs. If the file is loaded without parameters, it will display an HTML
form requesting a username and password. This type of form is shown in Figure 14.1.
Implementing Authentication with PHP and MySQL
C
HAPTER 14
14
IMPLEMENTING
AUTHENTICATION
305
FIGURE 14.1
Our HTML form requests that visitors enter a username and password for access.
If the parameters are present but not correct, it will display an error message. Our error mes-
sage is shown in Figure 14.2.
18 7842 CH14 3/6/01 3:35 PM Page 305


FIGURE 14.2
When users enter incorrect details, we need to give them an error message. On a real site, you might want to give a
somewhat friendlier message.
If these parameters are present and correct, it will display the secret content. Our test content is
shown in Figure 14.3.
E-commerce and Security
P
ART III
306
FIGURE 14.3
When provided with correct details, our script will display content.
The code to create the functionality shown in Figures 14.1, 14.2, and 14.3 is shown in
Listing 14.1.
LISTING 14.1 secret.php—PHP and HTML to Provide a Simple Authentication Mechanism
<?
if(!isset($name)&&!isset($password))
{
//Visitor needs to enter a name and password
?>
<h1>Please Log In</h1>
This page is secret.
18 7842 CH14 3/6/01 3:35 PM Page 306
<form method = post action = “secret.php”>
<table border = 1>
<tr>
<th> Username </th>
<td> <input type = text name = name> </td>
</tr>
<tr>
<th> Password </th>

<td> <input type = password name = password> </td>
</tr>
<tr>
<td colspan =2 align = center>
<input type = submit value = “Log In”>
</td>
</tr>
</table>
</form>
<?
}
else if($name==”user”&&$password==”pass”)
{
// visitor’s name and password combination are correct
echo “<h1>Here it is!</h1>”;
echo “I bet you are glad you can see this secret page.”;
}
else
{
// visitor’s name and password combination are not correct
echo “<h1>Go Away!</h1>”;
echo “You are not authorized to view this resource.”;
}
?>
The code from Listing 14.1 will give you a simple authentication mechanism to allow autho-
rized users to see a page, but it has some significant problems.
This script
• Has one username and password hard-coded into the script
• Stores the password as plain text
• Only protects one page

• Transmits the password as plain text
These issues can all be addressed with varying degrees of effort and success.
Implementing Authentication with PHP and MySQL
C
HAPTER 14
14
IMPLEMENTING
AUTHENTICATION
307
LISTING 14.1 Continued
18 7842 CH14 3/6/01 3:35 PM Page 307
Storing Passwords
There are many better places to store usernames and passwords than inside the script. Inside
the script, it is difficult to modify the data. It is possible, but a bad idea to write a script to
modify itself. It would mean having a script on your server, which gets executed on your
server, but is writable or modifiable by others. Storing the data in another file on the server will
let you more easily write a program to add and remove users and to alter passwords.
Inside a script or another data file, there is a limit to the number of users you can have without
seriously affecting the speed of the script. If you are considering storing and searching through
a large number of items in a file, you should consider using a database instead, as previously
discussed. As a rule of thumb, if you want to store and search through a list of more than 100
items, they should be in a database rather than a flat file.
Using a database to store usernames and passwords would not make the script much more
complex, but would allow you to authenticate many different users quickly. It would also allow
you to easily write a script to add new users, delete users, and allow users to change their pass-
words.
A script to authenticate visitors to a page against a database is given in Listing 14.2.
L
ISTING 14.2 secretdb.php—We Have Used MySQL to Improve Our Simple
Authentication Mechanism

<?
if(!isset($name)&&!isset($password))
{
//Visitor needs to enter a name and password
?>
<h1>Please Log In</h1>
This page is secret.
<form method = post action = “secretdb.php”>
<table border = 1>
<tr>
<th> Username </th>
<td> <input type = text name = name> </td>
</tr>
<tr>
<th> Password </th>
<td> <input type = password name = password> </td>
</tr>
<tr>
<td colspan =2 align = center>
<input type = submit value = “Log In”>
</td>
E-commerce and Security
P
ART III
308
18 7842 CH14 3/6/01 3:35 PM Page 308
</tr>
</table>
</form>
<?

}
else
{
// connect to mysql
$mysql = mysql_connect( ‘localhost’, ‘webauth’, ‘webauth’ );
if(!$mysql)
{
echo ‘Cannot connect to database.’;
exit;
}
// select the appropriate database
$mysql = mysql_select_db( ‘auth’ );
if(!$mysql)
{
echo ‘Cannot select database.’;
exit;
}
// query the database to see if there is a record which matches
$query = “select count(*) from auth where
name = ‘$name’ and
pass = ‘$password’”;
$result = mysql_query( $query );
if(!$result)
{
echo ‘Cannot run query.’;
exit;
}
$count = mysql_result( $result, 0, 0 );
if ( $count > 0 )
{

// visitor’s name and password combination are correct
echo “<h1>Here it is!</h1>”;
echo “I bet you are glad you can see this secret page.”;
}
else
{
Implementing Authentication with PHP and MySQL
C
HAPTER 14
14
IMPLEMENTING
AUTHENTICATION
309
LISTING 14.2 Continued
18 7842 CH14 3/6/01 3:35 PM Page 309
// visitor’s name and password combination are not correct
echo “<h1>Go Away!</h1>”;
echo “You are not authorized to view this resource.”;
}
}
?>
The database we are using can be created by connecting to MySQL as the MySQL root user
and running the contents of Listing 14.3.
LISTING 14.3 createauthdb.sql—These MySQL Queries Create the auth Database, the
auth Table, and Two Sample Users
create database auth;
use auth;
create table auth (
name varchar(10) not null,
pass varchar(30) not null,

primary key (name)
);
insert into auth values
(‘user’, ‘pass’);
insert into auth values
( ‘testuser’, password(‘test123’) );
grant select, insert, update, delete
on auth.*
to webauth@localhost
identified by ‘webauth’;
Encrypting Passwords
Regardless of whether we store our data in a database or a file, it is an unnecessary risk to
store the passwords as plain text. A one-way hashing algorithm can provide a little more secu-
rity with very little extra effort.
E-commerce and Security
P
ART III
310
LISTING 14.2 Continued
18 7842 CH14 3/6/01 3:35 PM Page 310
The PHP function crypt() provides a one-way cryptographic hash function. The prototype for
this function is
string crypt (string str [, string salt])
Given the string str, the function will return a pseudo-random string. For example, given the
string “pass” and the salt “xx”, crypt() returns “xxkT1mYjlikoII”. This string cannot be
decrypted and turned back into “pass” even by its creator, so it might not seem very useful at
first glance. The property that makes crypt() useful is that the output is deterministic. Given
the same string and salt, crypt() will return the same result every time it is run.
Rather than having PHP code like
if( $username == “user” && $password == “pass” )

{
//OK passwords match
}
we can have code like
if( $username == ‘user’ && crypt($password,’xx’) == ‘xxkT1mYjlikoII’ )
{
//OK passwords match
}
We do not need to know what ‘xxkT1mYjlikoII’ looked like before we used crypt() on it.
We only need to know if the password typed in is the same as the one that was originally run
through crypt().
As already mentioned, hard-coding our acceptable usernames and passwords into a script is a
bad idea. We should use a separate file or a database to store them.
If we are using a MySQL database to store our authentication data, we could either use the
PHP function crypt() or the MySQL function PASSWORD(). These functions do not produce
the same output, but are intended to serve the same purpose. Both crypt() and PASSWORD()
take a string and apply a non-reversible hashing algorithm.
To use PASSWORD(), we could rewrite the SQL query in Listing 14.2 as
select count(*) from auth where
name = ‘$name’ and
pass = password(‘$password’)
This query will count the number of rows in the table auth that have a name value equal to the
contents of $name and a pass value equal to the output given by PASSWORD() applied to the con-
tents of $password. Assuming that we force people to have unique usernames, the result of this
query will be either 0 or 1.
Implementing Authentication with PHP and MySQL
C
HAPTER 14
14
IMPLEMENTING

AUTHENTICATION
311
18 7842 CH14 3/6/01 3:35 PM Page 311
Protecting Multiple Pages
Making a script like this protect more than one page is a little harder. Because HTTP is state-
less, there is no automatic link or association between subsequent requests from the same per-
son. This makes it harder to have data, such as authentication information that a user has
entered, carry across from page to page.
The easiest way to protect multiple pages is to use the access control mechanisms provided by
your Web server. We will look at these shortly.
To create this functionality ourselves, we could include parts of the script shown in Listing
14.1 in every page that we want to protect. Using
auto_prepend_file and auto_append_file,
we can automatically prepend and append the code required to every file in particular directo-
ries. The use of these directives was discussed in Chapter 5, “Reusing Code and Writing
Functions.”
If we use this approach, what happens when our visitors go to multiple pages within our site?
It would not be acceptable to require them to re-enter their names and passwords for every
page they want to view.
We could append the details they entered to every hyperlink on the page. As users might have
spaces, or other characters that are not allowed in URLs, we should use the function
urlencode() to safely encode these characters.
There would still be a few problems with this approach though. Because the data would be
included in Web pages sent to the user, and the URLs they visit, the protected pages they visit
will be visible to anybody who uses the same computer and steps back through cached pages
or looks at the browser’s history list. Because we are sending the password back and forth to
the browser with every page requested or delivered, this sensitive information is being trans-
mitted more often than necessary.
There are two good ways to tackle these problems: HTTP basic authentication and sessions.
Basic authentication overcomes the caching problem, but the browser still sends the password

to the browser with every request. Session control overcomes both of these problems. We will
look at HTTP basic authentication now, and examine session control in Chapter 20, “Using
Session Control in PHP,” and in more detail in Chapter 24, “Building User Authentication and
Personalization.”
Basic Authentication
Fortunately, authenticating users is a common task, so there are authentication facilities built in
to HTTP. Scripts or Web servers can request authentication from a Web browser. The Web
E-commerce and Security
P
ART III
312
18 7842 CH14 3/6/01 3:35 PM Page 312
browser is then responsible for displaying a dialog box or similar device to get required infor-
mation from the user.
Although the Web server requests new authentication details for every user request, the Web
browser does not need to request the user’s details for every page. The browser generally stores
these details for as long as the user has a browser window open and automatically resends
them to the Web server as required without user interaction.
This feature of HTTP is called basic authentication. You can trigger basic authentication using
PHP, or using mechanisms built in to your Web server. We will look at the PHP method, the
Apache method, and the IIS method.
Basic authentication transmits a user’s name and password in plain text, so it is not very
secure. HTTP 1.1 contains a somewhat more secure method known as digest authentication,
which uses a hashing algorithm (usually MD5) to disguise the details of the transaction. Digest
authentication is supported by many Web servers, but is not supported by a significant number
of Web browsers. Digest authentication has been supported by Microsoft Internet Explorer
from version 5.0. At the time of writing, it is not supported by any version of Netscape
Navigator, but might be included in version 6.0.
In addition to being poorly supported by installed Web browsers, digest authentication is still
not very secure. Both basic and digest authentication provide a low level of security. Neither

gives the user any assurance that she is dealing with the machine she intended to access. Both
might permit a cracker to replay the same request to the server. Because basic authentication
transmits the user’s password as plain text, it allows any cracker capable of capturing packets
to impersonate the user for making any request.
Basic authentication provides a (low) level of security similar to that commonly used to con-
nect to machines via Telnet or FTP, transmitting passwords in plaintext. Digest authentication
is a little more secure, encrypting passwords before transmitting them. Using SSL and digital
certificates, all parts of a Web transaction can be protected by strong security.
If you want strong security, you should read the next chapter, Chapter 15, “Implementing
Secure Transactions with PHP and MySQL.” However, for many situations, a fast, but rela-
tively insecure, method such as basic authentication is appropriate.
Basic authentication protects a named realm and requires users to provide a valid username
and password. Realms are named so that more than one realm can be on the same server.
Different files or directories on the same server can be part of different realms, each protected
by a different set of names and passwords. Named realms also let you group multiple directo-
ries on the one host or virtual host as a realm and protect them all with one password.
Implementing Authentication with PHP and MySQL
C
HAPTER 14
14
IMPLEMENTING
AUTHENTICATION
313
18 7842 CH14 3/6/01 3:35 PM Page 313
Using Basic Authentication in PHP
PHP scripts are generally cross-platform, but using basic authentication relies on environment
variables set by the server. In order for an HTTP authentication script to run on Apache using
PHP as an Apache Module or on IIS using PHP as an ISAPI module, it needs to detect the
server type and behave slightly different. The script in Listing 14.4 will run on both servers.
LISTING 14.4 http.php—PHP Can Trigger HTTP Basic Authentication

<?
// if we are using IIS, we need to set $PHP_AUTH_USER and $PHP_AUTH_PW
if (substr($SERVER_SOFTWARE, 0, 9) == “Microsoft” &&
!isset($PHP_AUTH_USER) &&
!isset($PHP_AUTH_PW) &&
substr($HTTP_AUTHORIZATION, 0, 6) == “Basic “
)
{
list($PHP_AUTH_USER, $PHP_AUTH_PW) =
explode(“:”, base64_decode(substr($HTTP_AUTHORIZATION, 6)));
}
// Replace this if statement with a database query or similar
if ($PHP_AUTH_USER != “user” || $PHP_AUTH_PW != “pass”)
{
// visitor has not yet given details, or their
// name and password combination are not correct
header(‘WWW-Authenticate: Basic realm=”Realm-Name”’);
if (substr($SERVER_SOFTWARE, 0, 9) == “Microsoft”)
header(“Status: 401 Unauthorized”);
else
header(“HTTP/1.0 401 Unauthorized”);
echo “<h1>Go Away!</h1>”;
echo “You are not authorized to view this resource.”;
}
else
{
// visitor has provided correct details
echo “<h1>Here it is!</h1>”;
echo “<p>I bet you are glad you can see this secret page.”;
}

?>
E-commerce and Security
P
ART III
314
18 7842 CH14 3/6/01 3:35 PM Page 314

×