Session Authentication

Web site authentication applies to most Web sites on the Internet. Implementation of authentication schemes however can vary significantly from one site to another.

Why use session authentication?

Let’s say you run the Web site www.myneatstore.com and you want your customers to be authenticated with a username and password before they are allowed to make purchases. To accomplish this, you could use a number of methods (the most obvious of which is the HTTP authentication headers).

Unfortunately, to implement HTTP authentication you either have to properly configure it through your Web server (such as using a .htaccess file on an Apache Server) or duplicate the functionality through the use of the PHP header() function.

Although the HTTP mechanism is acceptable, even with a proper setup HTTP authentication has many shortcomings. These include:

  • the lack of useful security features, such as inactivity timeout
  • developer-friendly benefits, such as the ability to display secure/non secure data easily on the same page.
  • developing session authentication, you can overcome most of these shortcomings, while at the same time providing a more useful and clean implementation.

How do sessions work?

To understand how session authentication works, it is first necessary to understand how sessions work. If you are completely unfamiliar with sessions, consult the PHP manual on session functions.

Sessions were designed to solve a common problem in Web development — the lack of an efficient and clean way to transfer large amounts of user-specific data from one script to another seamlessly. For example, consider a series of scripts that require an array $foo to be passed from one script to another.

Using “conventional” methods, this array would have to be converted into a valid string to be passed through a GET or POST method to the next script. This script would then have to convert the data back to its original array form. This task can quickly become extremely difficult, and at times impossible, as the amount of data and number of involved scripts increases.

The concept behind sessions basically involves associating a single unique ID string with a (usually) much greater amount of actual data. This data can be anything PHP allows and in practice could represent our example array $foo.

When a user visits a session-enabled script, PHP checks for the existence of a session ID that may have been passed to the script (in the form of a cookie or GET method). If a session ID was passed, it is then checked for validity, and if valid the variables associated with that session ID are created.

If no session ID was provided, or the session ID provided was invalid, PHP creates a new ID that it then passes on to the browser (in either cookie form or by GET method). Through this mechanism, PHP ensures that in the event no valid session ID is given (as either a cookie or GET parameter to PHP when the page is requested), it is assigned one for future requests. In the event a valid session ID is given, all of the data associated with that session ID will be reloaded with identical values, and in the exact same state it was in when it was last accessed.

As a developer, this gives you the ability to write scripts seamlessly, even if they rely on variables that may have been created in other scripts executed independently of the current script.

How Session Authentication works

With this fundamental understanding of how sessions work, I’ll discuss how to develop an “authenticated” session. An authenticated session is nothing more than a session that contains variables that signify it as “authenticated”. For example, consider a session containing a variable array called $authdata that by default is not defined (is_array($authdata) is false).

If the array does not exist, the user is presented with a login form. At this point, assuming the user presents a valid username and password, $authdata is then set. Because $authdata is passed from script to script in the session, the user will not be asked to log in again for as long as the session ID remains valid.

Conversely, a user can be unauthenticated by unsetting $authdata using the unset() statement on it.

Here’s a step-by-step representation of this process:

  • Check the value of your authentication variables (in our case $authdata)
  • If the authentication variables fail, present a login page.
  1. Confirm the login information provided by the user with the server records (such as a username/password file on the server)
  2. Once confirmed, set appropriate authentication variables to reflect valid authentication
  • If authentication variables prove to be valid, display secure content

If this seems confusing, it is strongly recommended that you experiment with sessions and their behavior to gain a better understanding of sessions before continuing with today’s column.

The Script

Now it’s time to look at our script and show the practical side of today’s Code Gallery Spotlight column.

Today’s script is broken into two separate functions. The first, auth(), is the heart of the script and contains all of the necessary processing for the process to function and returns true if the session is to be considered authenticated.

The second function, loginform(), is nothing more than a wrapper for the HTML needed to display the login form and will not be discussed further. Let’s look at auth():

Code Flow

  • Start session and Init variables
  • Determine State (login check, auth check)

To begin the script, you need to first start the session by calling session_start(). When this function is called, the session process outlined earlier takes place and any variables that existed (such as $authdata) will automatically be created globally (which is then brought locally with the global statement). Once any registered variables have been created, you’ll then check for the existence of the $authdata array that signifies the session is authenticated.

Next, the script must determine the mode it is in. This can be done by checking the value of the optional $check variable; if the variable is set to true, then login information was provided.$check itself is determined by examining the $login parameter to see if it is empty or not. It is necessary only to check $login (instead of $login and $passwd) because $login is the only variable guaranteed to have a value (a password may not exist).

The next step is to determine if the script needs to check a username and password and if so, perform the check.

  • If $authdata already exists, session is authenticated so return true
  • If a login name/password was provided
  • Open the password file
  • Read line by line from the password file
  • Parse current line of the password file
  • Compare given login data with login data in the password file
  • If login data does not match any record in the password file, close it and return false and unset any previous authentication data
  • Return false if no login information was found

 

Assuming that there was a $login and $passwd parameter passed to your auth() function, the $check variable mentioned earlier should be true, and the script will then proceed to check the login information provided with that which is stored in the password file. The password file itself is broken down into the following format:

<username>,<password>

<username>,<password>

<username>,<password>

The first step is to open the password file for reading using fopen(). Once opened, the next step is to read a single line from the file and trim any extra white space from the start and end of the line using the trim() function.

Then, the line is broken into two variables, $l and $p, which represent the first two strings separated by a comma (the login and password respectively).

Next you’ll check the username and password with the ones provided to the script when the function was called. If they match, create the $authdata session variable, register it as a session variable, close the password file and return true. If no match is found for the current line, repeat the process with the next line of the password file until a match is found, or the end of the file has been reached.

If no username and password combination in the file match the one provided to the function, they are to be assumed invalid and the function shall return false. Again, this is all done only if $check is set to true.

Using the script

Using this script is a fairly simple process, and is best illustrated through an example. Consider the following:

 

This script is started by calling auth() with no parameters. If the session is already valid, there is no need to continue, and the authorized page can be displayed.

If the session is not valid, continue on by checking for the existence of a username and password. If they are provided, call auth(), again passing these parameters. If no username and password is provided, or they are invalid instead of displaying the authorized page, the script calls loginform() which displays the login form as shown and the process repeats until the session is authenticated.

Once authenticated, all subsequent requests of this page by that session will automatically be allowed until the session is unauthenticated or expires.

Final Notes

As always, there is room for improvement in any script. For instance, today’s Code Gallery Spotlight relies on plain-text username and password combinations. For better security, the crypt()function could have been used to encode any passwords to ensure that they remain secure. The script could also provide additional checks on $authdata (such as actually looking to see if there is a username and password keys within the array).

Here is a final example that illustrates how a page can be both authenticated and unauthenticated simultaneously using session authentication.

Because the login page is contained within a separate function, we can develop pages that only restrict certain content on that page to authenticated sessions. For example, consider the following:

In this case, all users will be able to see the first echo statement. But only those who have be authenticated prior to the execution of this script will be able to see the second.

There are many ways this script, and the concepts outlined today, can be used to improve not only your authentication, but many different aspects of your Web pages. Experiment with sessions and how they have been used here to accomplish user authentication — and be sure to submit any useful code snippets to the code gallery!