Section 14.2. Session Security


14.2. Session Security

Because a session may contain sensitive information, you need to treat the session as a possible security hole. Session security is necessary to create and implement a session. If someone is listening in or snooping on a network, it's possible that he can intercept a session ID and use it to look like he is someone else. It's also possible to access session data from the local filesystem on multiuser systems such as ISP hosting machines.

14.2.1. Session Hijacking and Session Fixation

Session hijacking is when someone accesses either a client's cookie or session ID, and then attempts to use this data. Session fixation is attempting to set your own session ID. Session fixation and hijacking are easy to combat. We'll make use of the super global variables for the client's IP address and browser type to keep things secure.

Example 14-8 demonstrates encoding the information with an md5 function call to thwart these potential security holes.

Example 14-8. Checking for session hijacking

 <?php session_start(); $user_check = md5($_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR']); if (empty($_SESSION['user_data'])) { session_regenerate_id(); echo ("New session, saving user_check."); $_SESSION['user_data'] = $user_check; } if (strcmp($_SESSION['user_data'], $user_check) !== 0) { session_regenerate_id(); echo ("Warning, you must reenter your session."); $_SESSION = array(); $_SESSION['user_data'] = $user_check; } else { echo ("Connection verified!"); } ?> 

When a browser first requests the page in Example 14-8, a session is started. In that session, we stored the encoded combination of the IP address and browser type. That way, when the user returns to this page, we can compare the value stored in the session versus a fresh computation of the IP address and browser type. If the two don't match, we potentially have a hijacker, so we pick a new ID and clear out any saved data for that session. That way, the hijacker cannot retrieve any of the private information stored in the session. This doesn't cause a problem for legitimate users, because they aren't going to change browser or IP addresses in the middle of a session with your web site.

Figure 14-9 shows the newly created session the first time the script runs.

Figure 14-9. The session is created and validates since it is a new session


Figure 14-10 shows what happens if the same script is executed again right away from the same browser.

Figure 14-10. The session is valid


Figure 14-11 mixes things up by copying the session ID cookie from the browser in Figure 14-9 and setting Internet Explorer on the same client machine to send a request with the same session ID.

Figure 14-11. The browser type change is caught


Because our script checks the type of browser, and it's changed from Firefox to Internet Explorer, the session is regenerated to prevent a security lapse.

14.2.2. Trusting User Data

You know that trusting data from a user isn't a great idea. But what exactly do you consider to be user data versus system data that you trust?


GET

Data from GET operations is inherently user data since it usually comes from form submissions.


POST

Data from POST operations is inherently user data since it usually comes from form submissions.


Cookies

Cookies may seem like they could be trusted since they are automatically sent, but in reality, since they are stored on the client's computer, they could be intentionally altered. Therefore, they're considered user data.


Session data

Session data can be trusted as long as the session value is set based on validated data. If it's set to a user-supplied value without validation, it's not trustworthy.

User input should be checked and escaped properly. Data that's bound for the database must have all special characters such as single and double quotes escaped. If PHP is not running with magic quotes on (discussed later in this chapter), then you'll need to pass user input through addslashes before sending it to the database.

Any user input that displays should be checked for embedded HTML that could be used for cross-site scripting attacks. The htmlspecialcharacters function is useful for escaping characters that have special meaning in HTML like less than (<) and greater than (>).

14.2.3. Shared Hosting Concerns

If you don't have your own dedicated server or are on a server that has multiple users, it can be very dangerous to use the default PHP settings to store your user's session data in a temporary directory. Normally, all users have access to that temporary directory, so they can easily pilfer private data from the session, including the session ID.

To make your session data more secure, you can set the session.save_path configuration parameter with the ini_set function to change the path where sessions are stored, as shown in Example 14-9. Make sure that these are stored below the web root directory.

Example 14-9. session.save_path functionality

 <?php     ini_set('session.save_path', '/home/user/sessions/');     session_start(); ?> 

Example 14-9 stores the sessions in the /home/user/sessions directory. Be sure that whichever folder you choose is created and has the correct permissions for the PHP interpreter to write the session data. Typically, this means the file must be writable by the permission group www-data. This folder shouldn't be readable or writable by general users at large.

14.2.4. Preventing Access to the Database

There are a couple of ways to reduce the chance that a malicious user can access your database. First, if there is a problem connecting to the database, the default MySQL error code reveals the location of the databasein other words, the IP address of the host. You'd like to suppress that information.

To prevent the standard error message from PHP, add the Error Control Operator, which is the at sign (@), to the front of the database function call. You'll experience a more closed-lipped or dubious error message in Example 14-10 before calling die to stop all processing.

Example 14-10. Suppressing the standard database error message

 <?php require_once('db_login.php'); $error = "Site down for maintenance, please check back."; $db_link = @mysql_connect($db_host, $db_username, $db_password) or die($error); @mysql_select_db($db_database, $db_link) or die($error); ?> 

Without the at sign (@) before the function calls, you'll see Figure 14-12.

Figure 14-12. The database server's location is revealed in the error message


From a security standpoint, notice how little the error message in Figure 14-13 reveals to a potential attacker about the environment.

Figure 14-13. We no longer give out more information than is necessary


While this may seem like a minor point, minimizing information available to hackers makes getting in much harder, providing you with more security.

14.2.5. Blocking Access to the Database for External Hosts

If your MySQL database server is on the same host as the web server, then it makes good sense to block access to the database port for external users. This can be done through the firewall setup utilities that are part of your operating system. The standard TCP/IP port number for MySQL is 3306. The port number is used to differentiate between services on the same host.

14.2.6. Create Separate Database Users

If you're running more than one application on your server, you should set up separate database users within MySQL for each application. That way, if there is a security breach in one of the applications, the data for the other application wouldn't be compromised. For example, if you have a bookstore web site, you can create all of your database objects to be accessible from a bookstore database account. Another site for employees to check their timesheets could then be set up using a separate database login. Each application continues to work well, and in the event of a security breach, the extent of damage is limited.

14.2.7. Magic Quotes

PHP attempts to shield developers from the danger of special characters being used in user input by a process called magic quotes. The escape characters such as single quotes (') and double quotes (") are escaped with slashes (\). By default, any data that comes from GET, POST, and cookies operations is automatically escaped. The escaping process is the same using the addslashes function on a string. When you send data that has special characters escaped to MySQL for insertion, MySQL automatically knows to convert the string back to the original values for storage in the database.

While magic quotes are good for beginners, they tend to create as many problems as they solve. Specifically, they waste some processing time, since all input is escaped regardless of whether it is bound for a database or may have been displayed.

Example 14-11 shows how magic quotes add an escape character to a value collected from a form.

Example 14-11. Seeing the results of magic quotes

 <?php $search=$_GET[search]; $self=$_SERVER['PHP_SELF']; if ($search != NULL ) {   echo "The search string is: <strong>$search</strong>."; } else {   echo ("<form action=\"$self\" ");   echo ('method="get">          <label> Search: <input type="text" name="search" > </label>          <input type="submit" value="Go!">          </form>         '); } ?> 

The entry in Figure 14-14 returns the screen in Figure 14-15.

Figure 14-14. Sending some test data with special characters


Figure 14-15. The string has its special characters escaped


Another annoyance with magic quotes is that you can't always assume magic_quotes are enabled if you're writing PHP code that might end up being installed on a variety of servers. The solution is to check whether it is enabled from within your code and call addslashes manually if it isn't. To check to see whether magic_quotes escaping is active, use the get_magic_quotes_gpc function. Example 14-12 shows how to check for magic quotes and call add_slashes if they are off.

Example 14-12. Checking for magic quotes

 <?php $search = $_GET["search"]; if (!get_magic_quotes_gpc()) { $search = addslashes($search); } if ($search != NULL ){ echo "The search string is: <strong>$search</strong>."; } else { echo '<form method="'.$_SERVER["PHP_SELF"].'" method="GET"> <label> Search: <input type="text" name="search"  /> </label> <input type="submit" value="Go!" /> </form>'; } ?> 

Again, whether magic quotes are enabled or not, it's up to you to be knowledgeable about how PHP and MySQL treat special characters. Be sure that your site not only works but is secure.

We've covered security and numerous issues to help you secure your web site. Next, we'll be discussing validation and error handling. We're very close to creating your blog. How exciting!



Learning PHP and MySQL
Learning PHP and MySQL
ISBN: 0596101104
EAN: 2147483647
Year: N/A
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net