cvs: phpdoc /en/chapters security.xml
| From: | Philip Olson | Date: | Fri, 16 May 2003 21:45:36 +0000 |
| Subject: | cvs: phpdoc /en/chapters security.xml | ||
| Groups: | php.doc | ||
| Request: | Send a blank email to phpdoc+get-969353548@lists.php.net to get a copy of this message | ||
philip Fri May 16 17:45:36 2003 EDT
Modified files:
/phpdoc/en/chapters security.xml
Log:
A complete rewrite of security.registerglobals to contain more information
and not make register_globals look so bad :)
Index: phpdoc/en/chapters/security.xml
diff -u phpdoc/en/chapters/security.xml:1.52 phpdoc/en/chapters/security.xml:1.53
--- phpdoc/en/chapters/security.xml:1.52 Wed Mar 26 21:35:18 2003
+++ phpdoc/en/chapters/security.xml Fri May 16 17:45:36 2003
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="iso-8859-1"?>
-<!-- $Revision: 1.52 $ -->
+<!-- $Revision: 1.53 $ -->
<chapter id="security">
<title>Security</title>
@@ -1023,80 +1023,138 @@
<sect1 id="security.registerglobals">
<title>Using Register Globals</title>
<para>
- One feature of PHP that can be used to enhance security is configuring PHP with
- <link linkend="ini.register-globals">register_globals</link> = off.
- By turning off the ability for any user-submitted variable to be injected
- into PHP code, you can reduce the amount of variable
- poisoning a potential attacker may inflict. They will have
- to take the additional time to forge submissions, and your
- internal variables are effectively isolated from user
- submitted data.
+ Perhaps the most controversial change in PHP is when the default value
+ for the PHP directive <link linkend="ini.register-globals">
+ register_globals</link> went from ON to OFF in PHP
+ <ulink url="&url.php.release4.2.0;">4.2.0</ulink>. Reliance on this
+ directive was quite common and many people didn't even know it existed
+ and assumed it's just how PHP works. This page will explain how one can
+ write insecure code with this directive but keep in mind that the
+ directive itself isn't insecure but rather it's the misuse of it.
+ </para>
+ <para>
+ When on, register_globals will inject (poison) your scripts will all
+ sorts of variables, like request variables from html forms. This
+ coupled with the fact that PHP doesn't require variable initializion
+ means writing insecure code is that much easier. It was a difficult
+ decision but the PHP community decided to disable this directive by
+ default. When on, people use variables yet really don't know for sure
+ where they come from and can only assume. Internal variables that are
+ defined in the script itself get mixed up with request data sent by
+ users and disabling register_globals changes this. Let's demonstrate
+ with an example misuse of register_globals:
</para>
<para>
- While it does slightly increase the amount of effort required
- to work with PHP, it has been argued that the benefits far
- outweigh the effort.
<example>
- <title>Working with register_globals=on</title>
+ <title>Example misuse with register_globals = on</title>
<programlisting role="php">
<![CDATA[
<?php
-if ($username) { // can be forged by a user in get/post/cookies
- $good_login = 1;
+// define $authorized = true only if user is authenticated
+if (authenticated_user()) {
+ $authorized = true;
}
-if ($good_login == 1) { // can be forged by a user in get/post/cookies,
- readfile ("/highly/sensitive/data/index.html");
+// Because we didn't first initialize $authenticated as false, this might be
+// defined through register_globals, like from GET auth.php?authenticated=1
+// So, anyone can be seen as authenticated!
+if ($authorized) {
+ include "/highly/sensitive/data.php";
}
?>
]]>
</programlisting>
</example>
+ </para>
+ <para>
+ When register_globals = on, our logic above may be compromised. When
+ off, <varname>$authorized</varname> can't be set via request so it'll
+ be okay although it really is good general programming practice to
+ initialize variables first. For example, in our example above we might
+ have first done <literal>$authorized = false</literal>. Doing this
+ first means our above code would work with register_globals on or off as
+ users by default would be unauthorized.
+ </para>
+ <para>
+ Another example is that of <link linkend="ref.session">sessions</link>.
+ When register_globals = on, we could also use
+ <varname>$username</varname> in our example below but again you must
+ realize that <varname>$username</varname> could also come from other
+ means, such as GET (through the URL).
+ </para>
+ <para>
<example>
- <title>Working with register_globals = off</title>
+ <title>Example use of sessions with register_globals on or off</title>
<programlisting role="php">
<![CDATA[
<?php
-if($_COOKIE['username']){
- // can only come from a cookie, forged or otherwise
- $good_login = 1;
- readfile ("/highly/sensitive/data/index.html");
+// We wouldn't know where $username came from but do know $_SESSION is
+// for session data
+if (isset($_SESSION['username'])) {
+
+ echo "Hello <b>{$_SESSION['username']}</b>";
+
+} else {
+
+ echo "Hello <b>Guest</b><br />";
+ echo "Would you like to login?";
+
}
?>
]]>
</programlisting>
</example>
- By using this wisely, it's even possible to take preventative
- measures to warn when forging is being attempted. If you know
- ahead of time exactly where a variable should be coming from,
- you can check to see if submitted data is coming from an
- inappropriate kind of submission. While it doesn't guarantee
- that data has not been forged, it does require an attacker
- to guess the right kind of forging.
+ </para>
+ <para>
+ It's even possible to take preventative measures to warn when forging is
+ being attempted. If you know ahead of time exactly where a variable
+ should be coming from, you can check to see if the submitted data is
+ coming from an inappropriate kind of submission. While it doesn't
+ guarantee that data has not been forged, it does require an attacker to
+ guess the right kind of forging. If you don't care where the request
+ data comes from, you can use <varname>$_REQUEST</varname> as it contains
+ a mix of GET, POST and COOKIE data. See also the manual section on
+ using <link linkend="language.variables.external">variables from outside
+ of PHP</link>.
+ </para>
+ <para>
<example>
<title>Detecting simple variable poisoning</title>
<programlisting role="php">
<![CDATA[
<?php
-if ($_COOKIE['username'] &&
- !$_POST['username'] &&
- !$_GET['username'] ) {
- // Perform other checks to validate the user name...
- $good_login = 1;
- readfile ("/highly/sensitive/data/index.html");
-} else {
+if (isset($_COOKIE['MAGIC_COOKIE'])) {
+
+ // MAGIC_COOKIE comes from a cookie.
+ // Be sure to validate the cookie data!
+
+} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {
+
mail("admin@example.com", "Possible breakin attempt",
$_SERVER['REMOTE_ADDR']);
echo "Security violation, admin has been alerted.";
exit;
+
+} else {
+
+ // MAGIC_COOKIE isn't set through this REQUEST
+
}
?>
]]>
</programlisting>
</example>
- Of course, simply turning off register_globals does not mean code
- is secure. For every piece of data that is submitted, it
- should also be checked in other ways.
</para>
+ <para>
+ Of course, simply turning off register_globals does not mean your code
+ is secure. For every piece of data that is submitted, it should also be
+ checked in other ways. Always validate your user data and initialize
+ your variables! To check for unitialized variables you may turn up
+ <function>error_reporting</function> to show
+ <constant>E_NOTICE</constant> level errors.
+ </para>
+
+ ¬e.superglobals;
+
</sect1>