9.8. Securing PHP's Form Processing9.8.1. ProblemYou want to securely process form input variables and not allow someone to maliciously alter variables in your code. 9.8.2. SolutionDisable the register_globals configuration directive and access variables only from the $_REQUEST array. To be even more secure, use $_GET , $_POST, and $_COOKIE to make sure you know exactly where your variables are coming from. To do this, make sure this line appears in your php.ini file: register_globals = Off As of PHP 4.2, this is the default configuration. 9.8.3. DiscussionWhen register_globals is set on, external variables, including those from forms and cookies, are imported directly into the global namespace. This is a great convenience, but it can also open up some security holes if you're not very diligent about checking your variables and where they're defined. Why? Because there may be a variable you use internally that isn't supposed to be accessible from the outside but has its value rewritten without your knowledge. Here is a simple example. You have a page in which a user enters a username and password. If they are validated, you return her user identification number and use that numerical identifier to look up and print out her personal information: // assume magic_quotes_gpc is set to Off $username = $dbh->quote($_GET['username']); $password = $dbh->quote($_GET['password']); $sth = $dbh->query("SELECT id FROM users WHERE username = $username AND password = $password"); if (1 == $sth->numRows( )) { $row = $sth->fetchRow(DB_FETCHMODE_OBJECT); $id = $row->id; } else { "Print bad username and password"; } if (!empty($id)) { $sth = $dbh->query("SELECT * FROM profile WHERE id = $id"); } Normally, $id is set only by your program and is a result of a verified database lookup. However, if someone alters the GET string, and passes in a value for $id, with register_globals enabled, even after a bad username and password lookup, your script still executes the second database query and returns results. Without register_globals, $id remains unset because only $_REQUEST['id'] (and $_GET['id']) are set. Of course, there are other ways to solve this problem, even when using register_globals. You can restructure your code not to allow such a loophole. $sth = $dbh->query("SELECT id FROM users WHERE username = $username AND password = $password"); if (1 == $sth->numRows( )) { $row = $sth->fetchRow(DB_FETCHMODE_OBJECT); $id = $row->id; if (!empty($id)) { $sth = $dbh->query("SELECT * FROM profile WHERE id = $id"); } } else { "Print bad username and password"; } Now you use $id only when it's been explicitly set from a database call. Sometimes, however, it is difficult to do this because of how your program is laid out. Another solution is to manually unset( ) or initialize all variables at the top of your script: unset($id); This removes the bad $id value before it gets a chance to affect your code. However, because PHP doesn't require variable initialization, it's possible to forget to do this in one place; a bug can then slip in without a warning from PHP. 9.8.4. See AlsoDocumentation on register_globals at http://www.php.net/security.registerglobals.php. Copyright © 2003 O'Reilly & Associates. All rights reserved. |
|