Right now, you can use authorize_user to check a user against a list of groups and either reject access to a page or allow the user to see a page. That means you have the logic to handle group-specific menus, but the actual implementation might take a bit of refactoring.
Take a look at your menu system as it stands
You can’t just drop the authorize_user function in here; it either gives a user access a page or disallows it. It’s not a fine-grained tool with which you can check group membership and get back a true or false value.
What you want is something like this:
Nothing here is new This is just a new riff on an old hit: the code yo live already got in . in the authorize_user function.
Get this code in place and then try it out. First, log in as a user who’s not in Administrators, Visit a page like and your menu options should not have a Manage Users options, as shown in Figure 14-3.
Now, sign out and do exactly the same thing again, this time with an administrative user. Magically-at least from the non-PHP programmer’s point of view-a new menu option appears. You can see the Manage Users link in Figure 14-4.
Entering Browser Sessions
So far, cookies have been the secret to much of your authentication and authorization success. But there are many programmers who really, really hate a cookie-only solution to storing a user’s information. The biggest issue with cookies is that they are entirely entities. This means that anything you store in a cookie resides in that cookie, on the user’s computer (the client device).
In your case the user’s 10 and user name are stored on your computer. In fact, on most wet browsers, you can easily look at your cookies. In Firefox for example you can click Preferences, select the Privacy tab and then click “Remove individual cookies.” Figure 14-5 shows the cookies related to your social networking app.
All of this information ends up residing on your users’ computers until those cookies expire. So, what’s a security-conscious programmer to do? Keep user IDs and similar information on the server, not the client side
Sessions Are Server-Side
Sessions are generally considered the answer to the vulnerability of cookies. Sessions are similar to cookies in that they can store information. However sessions have two big differences:
• Sessions are stored on the server rather than the client computer. People can’t view session data in a browser because there’s nothing to view except perhaps a non-readable 10 that connects a particular browser with a session
• Because sessions are stored on the server, you can use them to store much bigger chunks of data than cookies. You can store a user’s profile picture on the server in a session, for example, and not worry about taking up space on a user’s computer.
Because you’re not storing potentially sensitive information on the user’s computer many programmers prefer sessions.
Sessions Must Be Started
The biggest change in dealing with sessions isn’t lots of new syntax. In fact. you’ll quickly-see that changing from using cookies to sessions is pretty simple. But there’s one significant difference: before you can do any work with sessions, you must call session start:
From $_COOKIE to $_SESSION
This is where it gets easy: instead of using the superglobal $_COOKIE, you use the superglobal $_ SESSION. Yes, it’s that easy; simply make this change in
Now you use $_SESSION to both retrieve values from the session and insert values into the session. All the while, behind the scenes, all this information is stored on the server, rather than the client.
Sessions Must Be Restarted, Too
Here’s something a little strange. Try to sign in by using a good user name/password combination. You’re not going to see what you expect. Instead, you’ll get the error about not being logged in that’s illustrated in Figure 14-6
What’s going on? Think carefully; you might even want to search through Is this an error related to sessions as well as the obvious cookie-related issue? Well, kind of, but it’s generated by , not In fact, it’s actually an issue in authorize_user, which resides that function is called at the beginning of
When you think about it, it makes perfect sense that things aren’t behaving. authorize_user is expecting to find a user 10 in $_COOKIE
This looks better. Unfortunately, you’re going to get the exact same result. Sign in again, and you’ll get”Figure 14-7, yet another error. What’s going on now?
The secret is in the rather poorly named session start function. That function sounds like it starts a new session. In that case, you should call it once-as you did-in However, PHP scripts each run on their own, without connection to any other script. As a result, when is called, it has no idea that a session was started back in
In fact, there’s no connection at all between two scripts; they’re just two calls from a browser out there somewhere, hooked to the Internet via Wi-Fi or an Ethernet cable: So, how do two scripts-or an entire application’s worth of scripts-share this session data? The truth is a bit surprising: calling start_session actually creates a cookie on the client. Yes, you’re back to cookies!
Unlike other cookies you’ve seen so far, though, this one holds a fairly value (see Figure 14-8). This value refers to where a particular user’s data is stored on the server. It’s -a way to say, “Look up this code in all the server’s session data. Whatever’s there … that’s mine.”
What all of this means is that session start does a lot more than start a one-time session. It looks up a user’s cookie, and if it’s there, resreits the session that 10 references, so every script that wants to use $_ SESSION has to call session_start.
Fixing the problem in means two things: first. you need to call session_start in to ensure that session data is available to authorize_user and the other functions i
Try this out. and you’ll see an error pointing you to the second thing you’ve got to do. That error is a familiar one, and you can see it in Figure 14-9.
$_REQUEST Doesn’t Include $_SESSION
Here’s the line in that’s causing the problem:
// Get the user 1D of the user to show
$user id = $_REOUEST[‘user_id’];
This worked when you were using cookies for authorization because whether the user’s ID was in $_REQUEST$,_GET,$_POST,or $_COOKIE didn’t matter. All of these bubble up to $_REQUESTN. ow, however, you’re passing the user ID in a different superglobal, one not included in $_REQUEST$:_SESSION.
Not only that, you still have code in that passes the user ID in a request parameter:
Clearly, you can’t just switch $_ REQUEST to $_ SESSION and call it a day. Instead, you need to check both $_ SESSION and $_ REQUEST to cover all your bases:
Now, if there’s no user ID found in $_ REQUEST, the $_ SESSION is checked. And then, last but not least, you need to call session_start before you can do any work with the session
All that’s left is the menu that’s created It still uses $_COOKIE, but you know exactly what to do now. First, add the all-important call to session_start:
Be sure to check your menu; when you’re logged in, you should see Sign Out and My Profile. When you’re signed out, you shouldn’t
And Then, Sign Out …
That leads you back to signing but. With cookies, you set the expiration value to a time in the past. With $_SESSION,you need to call unset on the session variable
And, as odd as it might seem, you can’t work with $_SESSION-even if that work is to unset values-without calling session_start. Here’s what should look like:
The cookies are gone, and once runs, so will your user’s sessions variables
And just like that, with less than 20 lines of code changed, you’ve moved out of cookies and into sessions. Nice work! Your security-conscious users will thank you for it.
Memory Lane: Remember That Phishing Problem?
There’s just one little annoyance left to which you should attend. Remember the phishing problem back in It had to do with your use of error_message as a request parameter to snow snow_error.ctu: takes in the error message it displays from a request parameter
With sessions, you don’t have to settle for this security hole. The security problem stemmed from the fact that you were letting a request parameter handle the error message payload. But now, with sessions, you can remove those errors from view. This way, a hacker can’t possibly force-feed in a bad request parameter because you’re no longer using those parameters for that purpose.
That’s the .code that turns a PHP-supplied error into a request parameter. But now, you can rework this code using sessions:
Now, visit that page in your browser, You should see a response like that shown in Figure 14-11
This time, that phishing message is gone. Because the error message is stored in the session, it’s resistant to someone coming along and controlling the message via the URL. It’s a tiny change with huge implications for your users