Home arrow PHP arrow Page 5 - Professional PHP Programming

User Identification and Authentication - PHP

This is the first item in our Book Samples/Reviews section! This excerpt from Wrox Press Ltd.'s Professional PHP Programming covers Chapter 20 - Security. It shows you how to increase the security of your web site, not just by writing safe PHP scripts but also by configuring your webserver correctly. Buy it on Amazon.com now!

  1. Professional PHP Programming
  2. Contents
  3. The Importance of Security
  4. Securing your PHP Installation
  5. User Identification and Authentication
  6. Using Cryptography
  7. Secure transactions using SSL
  8. Installing a Private Key
  9. Creating Secure PHP Scripts
By: Dev Shed
Rating: starstarstarstarstar / 30
April 13, 2000

print this article


Every once in a while you will need to uniquely identify a user. Users are usually identified by a challenge and response system. A username/password combination is a good example of such a system, with the challenge being ‘Give me the secret password for Alice’ and the response being Alice’s secret password. This works because user Alice should be the only one who knows the secret password.

User Authentication by the Web Server
There is a standard way to authenticate users that requires minimal effort on the side of the PHP programmer. You can simply let Apache take care of authenticating the users.

AuthName      "Secret page"      # The realm AuthType      Basic   # The password file has been placed outside the web tree AuthUserFile   /home/car2001/website.pw   <LIMIT GET POST> require      valid-user </LIMIT>
You need to put these directives in a file called .htaccess in the directory you are trying to protect. You also need to create a file with the username/password combinations. You can do this with the htpasswd program that comes with Apache. Storing the password file inside the web tree is a bad idea, so place it somewhere safe outside the web tree and make sure that the permissions on the password file only allow the owner to view and modify the password file. Of course, the web server must be able to read the password file too.

If you now try to access a file in the protected directory, the web server asks the browser for a username and a password. The browser pops up a small input box where the user can type in their username and password. If the username/password combination matches the values in the password file, the user is allowed to access the page. If not, they get an error page telling them the web server could not authorize them. The realm is shown to the user so that they know which username and password to use.

The passwords are normally stored in an encrypted form, so even if a malicious user somehow gets their hands on the password file, they still wouldn’t know the passwords. If you know someone got their hands on the password file, you should probably generate new passwords for all the users listed in that file, since it is not impossible, though very hard, for this malicious user to come up with working passwords. That is, if you use passwords that are sufficiently random. The function below generates suitable passwords.

function randomPassword($length) {    $possible = '0123456789!@#$%^&*()_+' .                'abcdefghjiklmnopqrstuvwxyz' .                'ABCDEFGHIJKLMNOPQRSTUVWXYZ';    $str = "";    while (strlen($str) < $length) {       $str .= substr($possible, (rand() % strlen($possible)), 1);    }    return($str); }
Don’t forget to initialize the random generator with srand before calling this function or you may be generating the same set of passwords over and over again. It might be a good idea to use mt_rand instead of rand. Not only is mt_rand faster, it is also a better random generator and theoretically generates better passwords. To use mt_rand you need to change one line in the randomPassword function.

$str .= substr($possible, mt_rand(0, strlen($possible) - 1), 1);
You could initialize the random generator with something like this (works both for mt_srand and srand):

mt_srand((double)microtime() * 1000000);
Apache also supports digest authentication. Digest authentication works just like basic authentication, but the passwords are sent over the Internet in an encrypted form. While this does add security, digest authentication only works with Internet Explorer, which makes it almost impossible to use in most cases. You use htdigest instead of htpasswd to create the password file for digest authentication.
A small example is shown below.

<?php   if(!isset($PHP_AUTH_USER)) {     Header("WWW-Authenticate: Basic realm=\"Secret page\"");     Header("HTTP/1.0 401 Unauthorized");     echo "You did not log in correctly...\n";     exit; # exit will stop PHP from parsing the rest of the script   } else {     echo "Hello $PHP_AUTH_USER.<P>";     echo "You entered $PHP_AUTH_PW as your password.<P>";   } ?>
This can only be seen by someone who has logged in correctly. You can put this piece of code at the top of any page that needs authentication pages. Change the realm if you need different passwords for different sections. You could even have it automatically included in every page with the auto_prepend_file configuration option.

User Identification and Authentication with PHP
Doing user authentication in PHP has a lot going for it. It may be a bit more difficult, but the results are worth the extra effort. Below is a list of the many advantages of doing authentication from PHP.
  • It can be undone. A user can “log out”. This is not possible when you let Apache do the authentication.
  • It can expire. You can let logins expire after a certain time. For instance, if someone logged in and did not browse your site for 30 minutes, you could force them to authenticate themselves again.
  • It can be customized. You are only limited by your imagination and your technical skills. You have full control over the complete authentication process. You could for instance, use a small Java applet to send encrypted passwords over the Internet, which could be decrypted on the server with the mcrypt library. This would work with any browser that supports Java.
  • It can be database based. You can use all kinds of data from a database to authenticate users. You could keep a complete logfile of everyone visiting your website. (Note that Apache can get passwords from a database, for instance with the mod_auth_mysql module.)
  • It is per page. You can decide on a per-page basis if you need authentication, which pages are authenticated and which aren't. You can do something similar with Apache by changing the realm, but that is not as flexible.
  • It can be user authenticating and have optional registering. In registration mode, a user without a valid login is encouraged to register and an account is created for this user. The user is able to view the page however, with or without an account.
  • It works with CGI PHP. This is surely a big plus. While letting the webserver do the authentication will work with the CGI version of PHP, your script has no way of finding out who has been authenticated.
A simple but fully functional example is shown below.

<? if (!isset($password) || $password != "secret") {    ?>    <FORM ACTION="login.php3" METHOD=POST>    <TABLE><TR><TD><CENTER>    Password: <INPUT NAME=password TYPE=password><BR>    <INPUT TYPE=SUBMIT>    </CENTER></TD></TR></TABLE>    </FORM>    <? } else echo "This is password protected information." ?>
You can also have the browser display a dialog where the visitor can enter username and password information. This is done with the 401 HTTP status. This example retrieves the username and password combinations from a MySQL database.

<? if(!isset($PHP_AUTH_USER)) {    Header("WWW-authenticate: basic realm=\"restricted area\"");    Header( "HTTP/1.0 401 Unauthorized");    echo "You failed to provide the correct password...\n";    exit; } else {    mysql_select_db("users");    $user_id = strtolower($PHP_AUTH_USER);    $result = mysql_query("SELECT password FROM users " .                         "WHERE username = '$username'");    $row = mysql_fetch_array($result);    if ($PHP_AUTH_PW != $row["password"]) {      Header( "WWW-authenticate: basic realm=\"restricted area\"");      Header( "HTTP/1.0 401 Unauthorized");      echo "You failed to provide the correct password...\n";      exit;    } } ?>
Only users with a working username/password combination can see this.

You could also use a form the let the user input username and password. That way you have complete control over the layout of the HTML pages used.

Checking IP Addresses
People often think an IP address uniquely identifies a visitor. Unfortunately, this is not the case. Proxy servers may cause the requests of several visitors to come from the same IP address. If you were to use the IP address of those requests to identify users, you would in fact be checking the IP of the proxy server, which is probably not what you want. For instance, if you have an on-line poll and you allow one vote per IP address, you may only be allowing one vote per ISP. Another problem caused by proxy servers is the fact they may cause the requests from a single visitor to come from several different IP addresses. Multi-user systems and the use of IP masquerading also cause similar problems. This makes the use of an IP address to identify a user troublesome at best.

IP addresses do have their uses, but they are fairly limited. For instance, if you were running a forum and you were being harassed by a user posting abusive content, you could find out his IP address and ban anyone from that IP address. This is a last ditch method and usually doesn’t work very well. If the he uses a dial-up connection, he could simply reconnect to his ISP and get a new IP. If that ISP had a proxy server, you would be banning everyone who uses that ISP to connect to the Internet.

The following line will get the IP address that is associated with a particular request.


©1998 Wrox Press Limited, US and UK.

>>> More PHP Articles          >>> More By Dev Shed

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort


- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates


Dev Shed Tutorial Topics: