List:Commits« Previous MessageNext Message »
From:jon Date:January 18 2008 10:36pm
Subject:svn commit - mysqldoc@docsrva: r9606 - in trunk: refman-5.1 refman-6.0
View as plain text  
Author: jstephens
Date: 2008-01-18 22:36:15 +0100 (Fri, 18 Jan 2008)
New Revision: 9606

Log:

Added info about security concerns when using XPath and LOAD XML



Modified:
   trunk/refman-5.1/functions-core.xml
   trunk/refman-6.0/functions-core.xml
   trunk/refman-6.0/sql-syntax.xml


Modified: trunk/refman-5.1/functions-core.xml
===================================================================
--- trunk/refman-5.1/functions-core.xml	2008-01-18 17:45:03 UTC (rev 9605)
+++ trunk/refman-5.1/functions-core.xml	2008-01-18 21:36:15 UTC (rev 9606)
Changed blocks: 1, Lines Added: 208, Lines Deleted: 0; 7260 bytes

@@ -14179,6 +14179,214 @@
 
     </formalpara>
 
+    <formalpara>
+
+      <title>XPath Injection</title>
+
+      <para>
+        <firstterm>code injection</firstterm> occurs when malicious code
+        is introduced into the system to gain unauthorized access to
+        privileges and data. It is based on exploiting assumptions made
+        by developers about the type and content of data input from
+        users. XPath is no exception in this regard.
+      </para>
+
+    </formalpara>
+
+    <para>
+      A common scenario in which this can happen is the case of
+      application which handles authorization by matching the
+      combination of a login name and password with those found in an
+      XML file, using an XPath expression like this one:
+
+<programlisting>
+//user[login/text()='neapolitan' and password/text()='1c3cr34m']/attribute::id
+</programlisting>
+
+      This is the XPath equivalent of an SQL statement like this one:
+
+<programlisting>
+SELECT id FROM users WHERE login='neapolitan' AND password='1c3cr34m';
+</programlisting>
+    </para>
+
+    <para>
+      A PHP application employing XPath might handle the login process
+      like this:
+
+<programlisting>
+&lt;?php
+
+  $file     =   "users.xml";
+  
+  $login    =   $POST["login"];
+  $password =   $POST["password"];
+
+  $xpath = "//user[login/text()=$login and password/text()=$password]/attribute::id";
+
+  if( file_exists($file) )
+  {
+    $xml = simplexml_load_file($file);
+    
+    if($result = $xml-&gt;xpath($xpath))
+      echo "You are now logged in as user $result[0].";
+    else
+      echo "Invalid login name or password.";
+  }
+  else
+    exit("Failed to open $file.");
+  
+?&gt;
+</programlisting>
+
+      No checks are performed on the input. This means that a malevolent
+      user can <quote>short-circuit</quote> the test by entering
+      <literal>' or 1=1</literal> for both the login name and password,
+      resulting in <varname>$xpath</varname> being evaluated as shown
+      here:
+
+<programlisting>
+//user[login/text()='' or 1=1 and password/text()='' or 1=1]/attribute::id
+</programlisting>
+
+      Since the expression inside the square brackets always evaluates
+      as <literal>true</literal>, it is effectively the same as this
+      one, which matches the <literal>id</literal> attribute of every
+      <literal>user</literal> element in the XML document:
+
+<programlisting>
+//user/attribute::id
+</programlisting>
+
+      One way in which this particular attack can be circumvented is
+      simply by quoting the variable names to be interpolated in the
+      definition of <literal>$xpath</literal>, forcing the values passed
+      from a Web form to be converted to strings:
+
+<programlisting>
+$xpath = "//user[login/text()='$login' and password/text()='$password']/attribute::id";
+</programlisting>
+    </para>
+
+    <para>
+      This is the same strategy that is often recommended for preventing
+      SQL injection attacks. In general, the practices you should follow
+      for preventing XPath injection attacks are the same as for
+      preventing SQL injection:
+
+      <itemizedlist>
+
+        <listitem>
+          <para>
+            Never accepted untested data from users in your application.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Check all user-submited data for type; reject or convert
+            data that is of the wrong type
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Test numerical data for out of range values; truncate,
+            round, or reject values that are out of range. Test strings
+            for illegal characters and either strip them out or reject
+            input containing them.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Do not output explicit error messages that might provide an
+            unauthorized user with clues that could be used to
+            compromise the system; log these to a file or database table
+            instead.
+          </para>
+        </listitem>
+
+      </itemizedlist>
+
+      Just as SQL injection attacks can be used to obtain information
+      about database schemas, so can XPath injection be used to traverse
+      XML files to uncover their structure, as discussed in Amit
+      Klein&apos;s paper
+      <ulink
url="http://www.packetstormsecurity.org/papers/bypass/Blind_XPath_Injection_20040518.pdf">Blind
+      XPath Injection</ulink> (PDF file, 46KB).
+    </para>
+
+    <para>
+      It is also important to check the output being sent back to the
+      client. Consider what can happen when we use the MySQL
+      <function>ExtractValue()</function> function:
+
+<programlisting>
+mysql&gt; <userinput>SELECT ExtractValue(</userinput>
+    -&gt;     <userinput>LOAD_FILE('users.xml'),</userinput> 
+    -&gt;     <userinput>'//user[login/text()="" or 1=1 and password/text()=""
or 1=1]/attribute::id'</userinput> 
+    -&gt; <userinput>) AS id;</userinput>
++-------------------------------+
+| id                            |
++-------------------------------+
+| 00327 13579 02403 42354 28570 |
++-------------------------------+
+1 row in set (0.01 sec)
+</programlisting>
+
+      Because <function>ExtractValue()</function> returns multiple
+      matches as a single space-delimited string, this injection attack
+      provides every valid ID contained within
+      <filename>users.xml</filename> to the user as a single row of
+      output. As an extra safeguard, you should also test output before
+      returning it to the user. Here is a simple example:
+
+<programlisting>
+mysql&gt; <userinput>SELECT @id = ExtractValue(</userinput>
+    -&gt;     <userinput>LOAD_FILE('users.xml'),</userinput>
+    -&gt;     <userinput>'//user[login/text()="" or 1=1 and password/text()=""
or 1=1]/attribute::id'</userinput> 
+    -&gt; <userinput>);</userinput>
+Query OK, 0 rows affected (0.00 sec)
+
+mysql&gt; <userinput>SELECT IF(</userinput>
+    -&gt;     <userinput>INSTR(@id, ' ') = 0,</userinput> 
+    -&gt;     <userinput>@id,</userinput>
+    -&gt;     <userinput>'Unable to retrieve user ID')</userinput>
+    -&gt; <userinput>AS singleID;</userinput>
++----------------------------+
+| singleID                   |
++----------------------------+
+| Unable to retrieve user ID |
++----------------------------+
+1 row in set (0.00 sec)
+</programlisting>
+    </para>
+
+    <para>
+      In general, the guidelines for returning data to users securely
+      are the same as for accepting user input. These can be summed up
+      as:
+
+      <itemizedlist>
+
+        <listitem>
+          <para>
+            Always test outgoing data for type and allowable values.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Never allow unauthorized users to view error messages that
+            might provide information about the application that could
+            be used to exploit it.
+          </para>
+        </listitem>
+
+      </itemizedlist>
+    </para>
+
   </section>
 
   <section id="other-functions">


Modified: trunk/refman-6.0/functions-core.xml
===================================================================
--- trunk/refman-6.0/functions-core.xml	2008-01-18 17:45:03 UTC (rev 9605)
+++ trunk/refman-6.0/functions-core.xml	2008-01-18 21:36:15 UTC (rev 9606)
Changed blocks: 1, Lines Added: 208, Lines Deleted: 0; 7260 bytes

@@ -14450,6 +14450,214 @@
 
     </formalpara>
 
+    <formalpara>
+
+      <title>XPath Injection</title>
+
+      <para>
+        <firstterm>code injection</firstterm> occurs when malicious code
+        is introduced into the system to gain unauthorized access to
+        privileges and data. It is based on exploiting assumptions made
+        by developers about the type and content of data input from
+        users. XPath is no exception in this regard.
+      </para>
+
+    </formalpara>
+
+    <para>
+      A common scenario in which this can happen is the case of
+      application which handles authorization by matching the
+      combination of a login name and password with those found in an
+      XML file, using an XPath expression like this one:
+
+<programlisting>
+//user[login/text()='neapolitan' and password/text()='1c3cr34m']/attribute::id
+</programlisting>
+
+      This is the XPath equivalent of an SQL statement like this one:
+
+<programlisting>
+SELECT id FROM users WHERE login='neapolitan' AND password='1c3cr34m';
+</programlisting>
+    </para>
+
+    <para>
+      A PHP application employing XPath might handle the login process
+      like this:
+
+<programlisting>
+&lt;?php
+
+  $file     =   "users.xml";
+  
+  $login    =   $POST["login"];
+  $password =   $POST["password"];
+
+  $xpath = "//user[login/text()=$login and password/text()=$password]/attribute::id";
+
+  if( file_exists($file) )
+  {
+    $xml = simplexml_load_file($file);
+    
+    if($result = $xml-&gt;xpath($xpath))
+      echo "You are now logged in as user $result[0].";
+    else
+      echo "Invalid login name or password.";
+  }
+  else
+    exit("Failed to open $file.");
+  
+?&gt;
+</programlisting>
+
+      No checks are performed on the input. This means that a malevolent
+      user can <quote>short-circuit</quote> the test by entering
+      <literal>' or 1=1</literal> for both the login name and password,
+      resulting in <varname>$xpath</varname> being evaluated as shown
+      here:
+
+<programlisting>
+//user[login/text()='' or 1=1 and password/text()='' or 1=1]/attribute::id
+</programlisting>
+
+      Since the expression inside the square brackets always evaluates
+      as <literal>true</literal>, it is effectively the same as this
+      one, which matches the <literal>id</literal> attribute of every
+      <literal>user</literal> element in the XML document:
+
+<programlisting>
+//user/attribute::id
+</programlisting>
+
+      One way in which this particular attack can be circumvented is
+      simply by quoting the variable names to be interpolated in the
+      definition of <literal>$xpath</literal>, forcing the values passed
+      from a Web form to be converted to strings:
+
+<programlisting>
+$xpath = "//user[login/text()='$login' and password/text()='$password']/attribute::id";
+</programlisting>
+    </para>
+
+    <para>
+      This is the same strategy that is often recommended for preventing
+      SQL injection attacks. In general, the practices you should follow
+      for preventing XPath injection attacks are the same as for
+      preventing SQL injection:
+
+      <itemizedlist>
+
+        <listitem>
+          <para>
+            Never accepted untested data from users in your application.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Check all user-submited data for type; reject or convert
+            data that is of the wrong type
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Test numerical data for out of range values; truncate,
+            round, or reject values that are out of range. Test strings
+            for illegal characters and either strip them out or reject
+            input containing them.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Do not output explicit error messages that might provide an
+            unauthorized user with clues that could be used to
+            compromise the system; log these to a file or database table
+            instead.
+          </para>
+        </listitem>
+
+      </itemizedlist>
+
+      Just as SQL injection attacks can be used to obtain information
+      about database schemas, so can XPath injection be used to traverse
+      XML files to uncover their structure, as discussed in Amit
+      Klein&apos;s paper
+      <ulink
url="http://www.packetstormsecurity.org/papers/bypass/Blind_XPath_Injection_20040518.pdf">Blind
+      XPath Injection</ulink> (PDF file, 46KB).
+    </para>
+
+    <para>
+      It is also important to check the output being sent back to the
+      client. Consider what can happen when we use the MySQL
+      <function>ExtractValue()</function> function:
+
+<programlisting>
+mysql&gt; <userinput>SELECT ExtractValue(</userinput>
+    -&gt;     <userinput>LOAD_FILE('users.xml'),</userinput> 
+    -&gt;     <userinput>'//user[login/text()="" or 1=1 and password/text()=""
or 1=1]/attribute::id'</userinput> 
+    -&gt; <userinput>) AS id;</userinput>
++-------------------------------+
+| id                            |
++-------------------------------+
+| 00327 13579 02403 42354 28570 |
++-------------------------------+
+1 row in set (0.01 sec)
+</programlisting>
+
+      Because <function>ExtractValue()</function> returns multiple
+      matches as a single space-delimited string, this injection attack
+      provides every valid ID contained within
+      <filename>users.xml</filename> to the user as a single row of
+      output. As an extra safeguard, you should also test output before
+      returning it to the user. Here is a simple example:
+
+<programlisting>
+mysql&gt; <userinput>SELECT @id = ExtractValue(</userinput>
+    -&gt;     <userinput>LOAD_FILE('users.xml'),</userinput>
+    -&gt;     <userinput>'//user[login/text()="" or 1=1 and password/text()=""
or 1=1]/attribute::id'</userinput> 
+    -&gt; <userinput>);</userinput>
+Query OK, 0 rows affected (0.00 sec)
+
+mysql&gt; <userinput>SELECT IF(</userinput>
+    -&gt;     <userinput>INSTR(@id, ' ') = 0,</userinput> 
+    -&gt;     <userinput>@id,</userinput>
+    -&gt;     <userinput>'Unable to retrieve user ID')</userinput>
+    -&gt; <userinput>AS singleID;</userinput>
++----------------------------+
+| singleID                   |
++----------------------------+
+| Unable to retrieve user ID |
++----------------------------+
+1 row in set (0.00 sec)
+</programlisting>
+    </para>
+
+    <para>
+      In general, the guidelines for returning data to users securely
+      are the same as for accepting user input. These can be summed up
+      as:
+
+      <itemizedlist>
+
+        <listitem>
+          <para>
+            Always test outgoing data for type and allowable values.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Never allow unauthorized users to view error messages that
+            might provide information about the application that could
+            be used to exploit it.
+          </para>
+        </listitem>
+
+      </itemizedlist>
+    </para>
+
   </section>
 
   <section id="other-functions">


Modified: trunk/refman-6.0/sql-syntax.xml
===================================================================
--- trunk/refman-6.0/sql-syntax.xml	2008-01-18 17:45:03 UTC (rev 9605)
+++ trunk/refman-6.0/sql-syntax.xml	2008-01-18 21:36:15 UTC (rev 9606)
Changed blocks: 2, Lines Added: 64, Lines Deleted: 1; 3340 bytes

@@ -8867,7 +8867,7 @@
 
       <remark role="help-keywords">
         LOW_PRIORITY CONCURRENT LOCAL INFILE REPLACE IGNORE CHARACTER
-        SET ROWS IDENITIFIED BY LINES
+        SET ROWS IDENTIFIED BY LINES
       </remark>
 
       <remark role="help-syntax-begin"/>

@@ -9371,6 +9371,69 @@
         imported into the <literal>address</literal> table.
       </para>
 
+      <formalpara>
+
+        <title>Security Considerations</title>
+
+        <para>
+          As with the <literal>LOAD DATA</literal> statement, the
+          transfer of the XML file from the client host to the server
+          host is initiated by the MySQL server. In theory, a patched
+          server could be built that would tell the client program to
+          transfer a file of the server&apos;s choosing rather than the
+          file named by the client in the <literal>LOAD XML</literal>
+          statement. Such a server could access any file on the client
+          host to which the client user has read access.
+        </para>
+
+      </formalpara>
+
+      <para>
+        In a Web environment, clients usually connect to MySQL from a
+        Web server. A user that can run any command against the MySQL
+        server can use <literal>LOAD XML LOCAL</literal> to read any
+        files to which the Web server process has read access. In this
+        environment, the client with respect to the MySQL server is
+        actually the Web server, not the remote program being run by the
+        user who connects to the Web server.
+      </para>
+
+      <para>
+        You can disable loading of XML files from clients by starting
+        the server with <option>--local-infile=0</option> or
+        <option>--local-infile=OFF</option>. This option can also be
+        used when starting the <command>mysql</command> client to
+        disable <literal>LOAD XML</literal> for the duration of the
+        client session.
+      </para>
+
+      <para>
+        To prevent a client from loading XML files from the server, do
+        not grant the <literal>FILE</literal> privilege to the
+        corresponding MySQL user account, or revoke this privilege if
+        the client user account already has it.
+      </para>
+
+      <important>
+        <para>
+          Revoking the <literal>FILE</literal> privilege (or not
+          granting it in the first place) keeps the user only from
+          executing the <literal>LOAD XML INFILE</literal> statement (as
+          well as the <function>LOAD_FILE()</function> function; it does
+          <emphasis>not</emphasis> prevent the user from executing
+          <literal>LOAD XML LOCAL INFILE</literal>. To disallow this
+          statement, you must start the server or the client with
+          <option>--local-infile=OFF</option>.
+        </para>
+
+        <para>
+          In other words, the <literal>FILE</literal> privilege affects
+          only whether the client can read files on the server; it has
+          no bearing on whether the client can read files on the local
+          filesystem.
+        </para>
+      </important>
+
     </section>
 
     <section id="replace">


Thread
svn commit - mysqldoc@docsrva: r9606 - in trunk: refman-5.1 refman-6.0jon18 Jan