9.8.3. Discussion
When 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";
}