PHP

Authorizing other requests

The scripts shown in Example 9-8, Example 9-9, and Example 9-10 form a framework that manages the login and logout functions and sets up the authentication control session variables. Scripts that require authorization need to check the session variables before they generate any output.

The authorization code that checks the authentication control session variables, shown in Example 9-11, can be written to a separate file and included with each protected page using the include directive. This saves having to rewrite the code for each page that requires authorization.

Example 9-11 begins by initializing the session and calculating two Boolean flags. The first flag $notAuthenticated is set to true if the session variable $authenticatedUser isn't set. The second flag $notLoginIp is set to true only if the session variable $loginIpAddress is set and has the same value as the IP address of the client that sent this request. The IP address of the client that sent the request is available to scripts in the server environment variable $REMOTE_ADDR. Unlike with environment variables, PHP doesn't overwrite $REMOTE_ADDR by a GET or POST variable with the same name.

Both the $notAuthenticated flag and the $notLoginIp flag are tested, and if either is true, an appropriate $loginMessage is set and registered with the session, and then the Location: header field is sent with the HTTP response to relocate the browser back to the login script. The two cases are separated, because the script might be enhanced to record more information about the possible hijack attempt and even to destroy the session.

Example 9-11. Code that checks the authenticated state from the session variables
<?php
  session_start(  );
  $loginScript = "example.9-8.php";
  // Set a boolean flag to check if
  // a user has authenticated
  $notAuthenticated =
    !isset($HTTP_SESSION_VARS["authenticatedUser"]);
  // Set a boolean flag to true if this request
  // originated from the same IP address
  // as the one that created this session
  $notLoginIp =
    isset($HTTP_SESSION_VARS["loginIpAddress"])
    && ($HTTP_SESSION_VARS["loginIpAddress"] !=
        $REMOTE_ADDR);
  // Check that the two flags are false
  if($notAuthenticated)
  {
    // The request does not identify a session
    session_register("loginMessage");
    $loginMessage =
      "You have not been authorized to access the " .
      "URL $REQUEST_URI";
    // Re-locate back to the Login page
    header("Location: " . $loginScript);
    exit;
  }
  else if($notLoginIp)
  {
    // The request did not originate from the machine
    // that was used to create the session.
    // THIS IS POSSIBLY A SESSION HIJACK ATTEMPT
    session_register("loginMessage");
    $loginMessage =
      "You have not been authorized to access the " .
      "URL $REQUEST_URI from the address $REMOTE_ADDR";
    // Re-locate back to the Login page
    header("Location: " . $loginScript);
    exit;
  }
?>

To use the code developed in Example 9-11 to protect a page, we only need to include the file containing the code. If we saved Example 9-11 to auth.inc, protecting a page is easy:

<?php include("auth.inc"); ?>
<!DOCTYPE HTML PUBLIC
    "-//W3C//DTD HTML 4.0 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd" >
<html>
    ...
    <h2>Your Credit Card details</h2>
    ...
    <p><a href="example.9-10.php">Logout</a>
    ...
</html>

As discussed in Chapter 4, including files with the .inc extension presents a security problem. If the user requests the include file, the source of the include file is shown in the browser.

There are three ways to address this problem:

  • Store the include files outside the document tree of the Apache web server installation. For example, store the include files in the directory /usr/local/include/php and use the complete path in the include directive.

  • Use the extension .php instead of .inc. In this case, the include file is interpreted by the PHP script engine and produces no output because it contains no main body.

  • Configure Apache so that files with the extension .inc can't be retrieved.