Article

The PHP Anthology Volume 2, Chapter 1 - Access Control

Page: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Next

In response to a normal request for a page secured with basic HTTP authentication, a server might respond with headers like these:

HTTP/1.1 401 Authorization Required  
Date: Tue, 25 Feb 2003 15:41:54 GMT  
Server: Apache/1.3.27 (Unix) PHP/4.3.1  
X-Powered-By: PHP/4.3.1  
WWW-Authenticate: Basic realm="PHP Secured"  
Connection: close  
Content-Type: text/html

No further information is sent, but notice the status code HTTP/1.1 401 Authorization Required and the WWW-Authenticate header. Together, these indicate that the page is protected by HTTP authentication, and is not available to an unauthorized user. How a visitor's browser goes about dealing with this information may vary, but, usually, the user will see a small pop-up dialog box like that shown in Figure 1.1.

1279_fig1
Figure 1.1. Let Me In!

The dialog prompts site visitors to enter their user names and passwords. If visitors using Internet Explorer enter these login details incorrectly three times, the browser will display the "Unauthorized" message instead of displaying the prompt again. In other browsers, such as Opera, users may be able to continue trying indefinitely.

Notice that the realm value specified in the WWW-Authenticate header is displayed in the dialog box. A realm is a "security space" or "zone" within which a particular set of login details are valid. Upon successful authentication, the browser will remember the correct user name and password combination and automatically re-send it in any future request to that realm. When the user navigates to another realm, however, the browser displays a fresh prompt once again.

In any case, the user must provide a user name and password to get the page. The browser then sends those credentials with a second page request like this:

GET /admin/ HTTP/1.1  
Host: www.sitepoint.com  
Authorization: Basic jTSAbT766yN0hGjUi

The Authorization header contains the user name and password encoded with base64 encoding which, it is worth noting, is not secure—but at least makes it unreadable for humans.

The server will check to ensure that the credentials are valid. If they are not, the server will send the Authorization Required response again, as shown previously. If the credentials are valid, the server will send the requested page as normal.

Not by the Hairs of my Chin…

Now that you have a rough idea of how HTTP authentication works, how might you secure a PHP page with it? When PHP receives an Authorization header from a Web browser, it automatically decodes the user name and password combination and stores the values in the variables $_SERVER['PHP_AUTH_USER'] and $_SERVER['PHP_AUTH_PW'] for the user name and password, respectively. Here's how you could secure a simple page:

Example 1.2. 2.php  
 
<?php  
// An array of allowed users and their passwords  
$users = array(  
 'harryf' => 'secret',  
 'littlepig' => 'chinny'  
);  
 
// If there's no Authentication header, exit  
if (!isset($_SERVER['PHP_AUTH_USER'])) {  
 header('HTTP/1.1 401 Unauthorized');  
 header('WWW-Authenticate: Basic realm="PHP Secured"');  
 exit('This page requires authentication');  
}  
 
// If the user name doesn't exist, exit  
if (!isset($users[$_SERVER['PHP_AUTH_USER']])) {  
 header('HTTP/1.1 401 Unauthorized');  
 header('WWW-Authenticate: Basic realm="PHP Secured"');  
 exit('Unauthorized!');  
}  
 
// Is the password doesn't match the username, exit  
if ($users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW'])  
{  
 header('HTTP/1.1 401 Unauthorized');  
 header('WWW-Authenticate: Basic realm="PHP Secured"');  
 exit('Unauthorized!');  
}  
 
echo 'You\'re in';  
?>

First, the script checks to see if an authentication has been sent by the browser; if it hasn't, the script sends the Authorization Required headers and terminates. If login details were submitted, it checks that the submitted user name actually exists. If we hadn't checked this, we'd get a PHP notice stating that the array key didn't exist when performing the third check on particular PHP configurations (see Chapter 10, Error Handling). The third check ensures that the user name and password combination in the $users array matches the details sent by the Web browser.

Note that we could also have checked the user name and password against a table in a database—something we'll look at in the section called "How do I authenticate users with sessions?".

When to Send Headers

In PHP, the moment your script outputs anything that's meant for display, the Web server finishes sending the headers and begins to send the content itself. You cannot send further HTTP headers once the body of the HTTP message—the Web page itself—has begun to be sent. This means that if you use the header function or session_start after the body has begun, you'll get an error message like this:

Warning: Cannot add header information - headers already  
sent by (output started at…

Remember, any text or whitespace outside the <?php … ?> tags causes output to be sent to the browser. If you have whitespace before a <?php tag or after a ?> tag, you won't be able to send headers to the browser past that point.

This type of authentication is handy in that it's easy to implement, but it's none too pretty in terms of the user experience. It does present a useful authentication mechanism for use with Web services, however—something we'll see in Chapter 2, XML.

Note that PEAR provides the Auth_HTTP package, which you should consider if you're planning to use HTTP authentication in earnest, as it will help you avoid making critical errors. For a detailed discussion of PEAR, consult Appendix D, Working with PEAR.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links