ronabop         Sat Jul 28 17:57:49 2001 EDT

  Modified files:              
    /phpdoc/en/chapters security.xml 
  Log:
  Enhancing, per recent discussions on PHP-DEV, and adding section on using 
register_globals to increase security.
  
Index: phpdoc/en/chapters/security.xml
diff -u phpdoc/en/chapters/security.xml:1.19 phpdoc/en/chapters/security.xml:1.20
--- phpdoc/en/chapters/security.xml:1.19        Tue May  8 17:30:06 2001
+++ phpdoc/en/chapters/security.xml     Sat Jul 28 17:57:49 2001
@@ -265,29 +265,37 @@
     "nobody" user. This means a malicious script could access and modify
     the database, even without a username and password. It's entirely
     possible that a web spider could stumble across a database
-    adminisitror's web page, and drop all of your databases. You can
+    administrator's web page, and drop all of your databases. You can
     protect against this with Apache authorization, or you can design
     your own access model using LDAP, .htaccess files, etc. and include
     that code as part of your PHP scripts.
    </simpara>
    <simpara>
     Often, once security is established to the point where the PHP user
-    (in this case, the apache user) has very little risk, it is
-    discovered that PHP now has been prevented from writing virus files
+    (in this case, the apache user) has very little risk attached to it,
+    it is discovered that PHP is now prevented from writing any files
     to user directories. Or perhaps it has been prevented from accessing
-    or changing a non-public database. It has equally been secured from
-    writing files that it should, or entering database transactions.
+    or changing databases. It has equally been secured from writing
+    good and bad files, or entering good and bad database transactions.
    </simpara>
    <simpara>
     A frequent security mistake made at this point is to allow apache
-    root permissions.
+    root permissions, or to escalate apache's abilitites in some other
+    way.
    </simpara>
    <simpara>
     Escalating the Apache user's permissions to root is extremely
     dangerous and may compromise the entire system, so sudo'ing,
-    chroot'ing ,or otherwise running as root should not be considered by
+    chroot'ing, or otherwise running as root should not be considered by
     those who are not security professionals.
    </simpara>
+   <simpara>
+    There are some simpler solutions. By using 
+    <function>open_basedir()</function> you can control and restrict what
+    directories are allowed to be used for PHP. You can also set up
+    apache-only areas, to restrict all web based activity to non-user,
+    or non-system, files.
+   </simpara>
   </sect1>
 
   <sect1 id="security.filesystem">
@@ -369,7 +377,7 @@
 &lt;?php
 // removes a file from the hard drive that
 // the PHP user has access to. 
-$username = $HTTP_REMOTE_USER; // use an authentication mechanisim
+$username = $HTTP_REMOTE_USER; // using an authentication mechanisim
 
 $homedir = "/home/$username";
 
@@ -385,21 +393,28 @@
 ?&gt;
      </programlisting>
     </example>
-    Alternately, you may prefer to write a more customized check:
+    However, even this is not without it's flaws. If your authentication
+    system allowed users to create their own user logins, and a user
+    chose the login "../etc/", the system is once again exposed. For
+    this reason, you may prefer to write a more customized check:
     <example>
      <title>More secure file name checking</title>
      <programlisting role="php">
 &lt;?php
-$username = getenv("REMOTE_USER");
+$username = $HTTP_REMOTE_USER; // using an authentication mechanisim
 $homedir = "/home/$username";
 
 if (!ereg('^[^./][^/]*$', $userfile))
-    die('bad filename'); //die, do not process
-    
+     die('bad filename'); //die, do not process
+     
+if (!ereg('^[^./][^/]*$', $username))
+     die('bad username'); //die, do not process    
 //etc...
 ?&gt;
      </programlisting>
     </example> 
+   </para>
+   <para>
     Depending on your operating system, there are a wide variety of files
     which you should be concerned about, including device entries (/dev/
     or COM1), configuration files (/etc/ files and the .ini files),
@@ -411,13 +426,29 @@
 
   <sect1 id="security.errors">
    <title>Error Reporting</title>
-   <simpara>
+   <para>
+    With PHP security, there are two sides to error reporting. One is
+    beneficial to increasing security, the other is detrimental.
+   </para>
+   <para>
     A standard attack tactic involves profiling a system by feeding
     it improper data, and checking for the kinds, and contexts, of the
     errors which are returned. This allows the system cracker to probe
     for information about the server, to determine possible weaknesses.
-   </simpara>
-   <simpara>
+    For example, if an attacker had gleaned information about a page
+    based on a prior form submission, they may attempt to override
+    variables, or modify them:
+    <example>
+     <title>Attacking Variables with a custom HTML page</title>
+     <programlisting role="php">
+&lt;form method="post" action="attacktarget?username=badfoo&amp;password=badfoo"&gt;
+&lt;input type="hidden" name="username" value="badfoo"&gt;
+&lt;input type="hidden" name="password" value="badfoo"&gt;
+&lt;/form&gt;
+     </programlisting>
+    </example> 
+   </para>
+   <para>
     The PHP errors which are normally returned can be quite helpful to a
     developer who is trying to debug a script, indicating such things
     as the function or file that failed, the PHP file it failed in,
@@ -427,16 +458,35 @@
     <function>highlight_string</function>, or 
     <function>highlight_file</function> as a debugging measure, but in 
     a live site, this can expose hidden variables, unchecked syntax, 
-    and other dangerous information.
-   </simpara>
-   <simpara>
-    For example, the very style of a generic error indicates a system
+    and other dangerous information. Especially dangerous is running
+    code from known sources with built-in debugging handlers, or using
+    common debugging techniques. If the attacker can determine what
+    general technique you are using, they may try to brute-force a page,
+    by sending various common debugging strings:
+    <example>
+     <title>Exploiting common debugging variables</title>
+     <programlisting role="php">
+&lt;form method="post" 
+action="attacktarget?errors=Y&amp;showerrors=1"&amp;debug=1"&gt;
+&lt;input type="hidden" name="errors" value="Y"&gt;
+&lt;input type="hidden" name="showerrors" value="1"&gt;
+&lt;input type="hidden" name="debug" value="1"&gt;
+&lt;/form&gt;
+     </programlisting>
+    </example>     
+   </para>
+   <para>
+    Regardless of the method of error handling, the ability to probe a
+    system for errors leads to providing an attacker with more
+    information.
+   </para>
+   <para>
+    For example, the very style of a generic PHP error indicates a system
     is running PHP. If the attacker was looking at an .html page, and
     wanted to probe for the back-end (to look for known weaknesses in
     the system), by feeding it the wrong data they may be able to
     determine that a system was built with PHP.
-   </simpara>
-   <simpara>
+   </para>
+   <para>
     A function error can indicate whether a system may be running a
     specific database engine, or give clues as to how a web page or
     programmed or designed. This allows for deeper investigation into
@@ -445,15 +495,15 @@
     an attacker can determine the order of authentication in a script,
     (from the line number errors) as well as probe for exploits that
     may be exploited in different locations in the script.
-   </simpara>
-   <simpara>
+   </para>
+   <para>
     A filesystem or general PHP error can indicate what permissions
     the webserver has, as well as the structure and organization of
     files on the web server. Developer written error code can aggravate
     this problem, leading to easy exploitation of formerly "hidden"
     information.
-   </simpara>
-   <simpara>
+   </para>
+   <para>
     There are three major solutions to this issue. The first is to
     scrutinize all functions, and attempt to compensate for the bulk
     of the errors. The second is to disable error reporting entirely
@@ -461,8 +511,93 @@
     handling functions to create your own error handler. Depending
     on your security policy, you may find all three to be applicable
     to your situation.
-   </simpara>
+   </para>
+   <para>
+    One way of catching this issue ahead of time is to make use of
+    PHP's own <function>error_reporting()</function>, to help you
+    secure your code and find variable usage that may be dangerous.
+    By testing your code, prior to deployment, with E_ALL, you can
+    quickly find areas where your variables may be open to poisoning
+    or modification in other ways. Once you are ready for deployment,
+    by using E_NONE, you insulate your code from probing.
+    <example>
+     <title>Finding dangerous variables with E_ALL</title>
+     <programlisting role="php">
+&lt;?php
+if ($username) {  // Not initialized or checked before usage
+    $good_login = 1; 
+}
+if ($good_login == 1) { // If above test fails, not initialized or checked before 
+usage
+    fpassthru ("/highly/sensitive/data/index.html");
+}
+?&gt;
+     </programlisting>
+    </example>
+   </para>
   </sect1>
+
+  <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 register_globals = off. By turning off
+    the ability for any user-submitted variable to be injected
+    into PHP code, you can restrict the amount of variable
+    poisoning a potential attacker may inflict.
+   </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 without register_globals=off</title>
+     <programlisting role="php">
+&lt;?php
+if ($username) {  // can be forged by a user in get/post/cookies
+    $good_login = 1; 
+}
+
+if ($good_login == 1) { // can be forged by a user in get/post/cookies,
+    fpassthru ("/highly/sensitive/data/index.html");
+}
+?&gt;
+     </programlisting>
+    </example>
+    <example>
+     <title>Working with register_globals = off</title>
+     <programlisting role="php">
+&lt;?php
+if($HTTP_COOKIE_VARS["username"]){  // can only come from a cookie
+    $good_login = 1; // cannot be forged by a user
+    fpassthru ("/highly/sensitive/data/index.html");
+}
+?&gt;
+     </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 inappropriate.
+    <example>
+     <title>Detecting variable poisoning</title>
+     <programlisting role="php">
+&lt;?php
+if ($HTTP_COOKIE_VARS["username"] &&
+    !$HTTP_POST_VARS["username"] &&
+    !$HTTP_GET_VARS["username"] ) { 
+    $good_login = 1;
+    fpassthru ("/highly/sensitive/data/index.html");
+} else {
+   mail("[EMAIL PROTECTED]", "Possible breakin attempt", "$REMOTE_IP_ADDR");
+   echo "Security violation, admin has been alerted.";
+   exit;
+}
+?&gt;
+     </programlisting>
+    </example>
+   </para>
+  </sect1>
+
   
   <sect1 id="security.variables">
    <title>User Submitted Data</title>
@@ -480,7 +615,7 @@
 // somebody else's?
 unlink ($evil_var);
 
-// Write logging of their access... or maybe not?
+// Write logging of their access... or maybe an /etc/password entry?
 fputs ($fp, $evil_var);
 
 // Execute something trivial.. or rm -rf *?
@@ -537,7 +672,7 @@
     operated upon).
    </para>
   </sect1>
-
+  
   <sect1 id="security.general">
    <title>General considerations</title>
    <simpara>

Reply via email to