<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/security.database.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'en',
  ),
  'this' => 
  array (
    0 => 'security.database.sql-injection.php',
    1 => 'SQL Injection',
    2 => 'SQL Injection',
  ),
  'up' => 
  array (
    0 => 'security.database.php',
    1 => 'Database Security',
  ),
  'prev' => 
  array (
    0 => 'security.database.storage.php',
    1 => 'Encrypted Storage Model',
  ),
  'next' => 
  array (
    0 => 'security.errors.php',
    1 => 'Error Reporting',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'en',
    'path' => 'security/database.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="security.database.sql-injection" class="sect1">
    <h2 class="title">SQL Injection</h2>
    <p class="simpara">
     SQL injection is a technique where an attacker exploits flaws in
     application code responsible for building dynamic SQL queries.
     The attacker can gain access to privileged sections of the application,
     retrieve all information from the database, tamper with existing data,
     or even execute dangerous system-level commands on the database
     host. The vulnerability occurs when developers concatenate or
     interpolate arbitrary input in their SQL statements.
    </p>
    <p class="para">
     <div class="example" id="example-1">
      <p><strong>Example #1 
       Splitting the result set into pages ... and making superusers
       (PostgreSQL)
      </strong></p>
      <div class="example-contents"><p>
       In the following example, user input is directly interpolated into the
       SQL query allowing the attacker to gain a superuser account in the database.
      </p></div>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$offset </span><span style="color: #007700">= </span><span style="color: #0000BB">$_GET</span><span style="color: #007700">[</span><span style="color: #DD0000">'offset'</span><span style="color: #007700">]; </span><span style="color: #FF8000">// beware, no input validation!<br /></span><span style="color: #0000BB">$query  </span><span style="color: #007700">= </span><span style="color: #DD0000">"SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET </span><span style="color: #0000BB">$offset</span><span style="color: #DD0000">;"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$result </span><span style="color: #007700">= </span><span style="color: #0000BB">pg_query</span><span style="color: #007700">(</span><span style="color: #0000BB">$conn</span><span style="color: #007700">, </span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
      Normal users click on the &#039;next&#039;, &#039;prev&#039; links where the <var class="varname">$offset</var>
      is encoded into the <abbr title="Uniform Resource Locator">URL</abbr>. The script expects that the incoming
      <var class="varname">$offset</var> is a number. However, what if someone tries to
      break in by appending the following to the <abbr title="Uniform Resource Locator">URL</abbr>
      <div class="informalexample">
       <div class="example-contents">
<div class="sqlcode"><pre class="sqlcode">0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
    select &#039;crack&#039;, usesysid, &#039;t&#039;,&#039;t&#039;,&#039;crack&#039;
    from pg_shadow where usename=&#039;postgres&#039;;
--</pre>
</div>
       </div>

      </div>
      If it happened, the script would present a superuser access to the attacker.
      Note that <code class="literal">0;</code> is to supply a valid offset to the
      original query and to terminate it.
    </p>
    <blockquote class="note"><p><strong class="note">Note</strong>: 
     <p class="para">
      It is a common technique to force the SQL parser to ignore the rest of the
      query written by the developer with <code class="literal">--</code> which is the
      comment sign in SQL.
     </p>
    </p></blockquote>
    <p class="para">
     A feasible way to gain passwords is to circumvent your search result pages.
     The only thing the attacker needs to do is to see if there are any submitted variables
     used in SQL statements which are not handled properly. These filters can be set
     commonly in a preceding form to customize <code class="literal">WHERE, ORDER BY,
     LIMIT</code> and <code class="literal">OFFSET</code> clauses in <code class="literal">SELECT</code>
     statements. If your database supports the <code class="literal">UNION</code> construct,
     the attacker may try to append an entire query to the original one to list
     passwords from an arbitrary table. It is strongly recommended to store only
     secure hashes of passwords instead of the passwords themselves.
     <div class="example" id="example-2">
      <p><strong>Example #2 
       Listing out articles ... and some passwords (any database server)
      </strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$query  </span><span style="color: #007700">= </span><span style="color: #DD0000">"SELECT id, name, inserted, size FROM products<br />           WHERE size = '</span><span style="color: #0000BB">$size</span><span style="color: #DD0000">'"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$result </span><span style="color: #007700">= </span><span style="color: #0000BB">odbc_exec</span><span style="color: #007700">(</span><span style="color: #0000BB">$conn</span><span style="color: #007700">, </span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
     The static part of the query can be combined with another
     <code class="literal">SELECT</code> statement which reveals all passwords:
     <div class="informalexample">
      <div class="example-contents">
<div class="sqlcode"><pre class="sqlcode">&#039;
union select &#039;1&#039;, concat(uname||&#039;-&#039;||passwd) as name, &#039;1971-01-01&#039;, &#039;0&#039; from usertable;
--</pre>
</div>
      </div>

     </div>
    </p>
    <p class="para">
     <code class="literal">UPDATE</code> and <code class="literal">INSERT</code> statements are also
     susceptible to such attacks.
     <div class="example" id="example-3">
     <p><strong>Example #3 
      From resetting a password ... to gaining more privileges (any database server)
     </strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$query </span><span style="color: #007700">= </span><span style="color: #DD0000">"UPDATE usertable SET pwd='</span><span style="color: #0000BB">$pwd</span><span style="color: #DD0000">' WHERE uid='</span><span style="color: #0000BB">$uid</span><span style="color: #DD0000">';"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
     If a malicious user submits the value
     <code class="literal">&#039; or uid like&#039;%admin%</code> to <var class="varname">$uid</var> to
     change the admin&#039;s password, or simply sets <var class="varname">$pwd</var> to
     <code class="literal">hehehe&#039;, trusted=100, admin=&#039;yes</code> to gain more 
     privileges, then the query will be twisted:
     <div class="informalexample">
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">// $uid: ' or uid like '%admin%<br /></span><span style="color: #0000BB">$query </span><span style="color: #007700">= </span><span style="color: #DD0000">"UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%';"</span><span style="color: #007700">;<br /><br /></span><span style="color: #FF8000">// $pwd: hehehe', trusted=100, admin='yes<br /></span><span style="color: #0000BB">$query </span><span style="color: #007700">= </span><span style="color: #DD0000">"UPDATE usertable SET pwd='hehehe', trusted=100, admin='yes' WHERE<br />...;"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
    </p>
    <p class="simpara">
     While it remains obvious that an attacker must possess at least some
     knowledge of the database architecture to conduct a successful
     attack, obtaining this information is often very simple. For example,
     the code may be part of an open-source software and be publicly available.
     This information may also be divulged
     by closed-source code - even if it&#039;s encoded, obfuscated, or compiled -
     and even by your own code through the display of error messages.
     Other methods include the use of typical table and column names.  For
     example, a login form that uses a &#039;users&#039; table with column names
     &#039;id&#039;, &#039;username&#039;, and &#039;password&#039;.
    </p>
    <p class="para">
     <div class="example" id="example-4">
     <p><strong>Example #4 Attacking the database host operating system (MSSQL Server)</strong></p>
      <div class="example-contents"><p>
       A frightening example of how operating system-level commands can be
       accessed on some database hosts.
      </p></div>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$query  </span><span style="color: #007700">= </span><span style="color: #DD0000">"SELECT * FROM products WHERE id LIKE '%</span><span style="color: #0000BB">$prod</span><span style="color: #DD0000">%'"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$result </span><span style="color: #007700">= </span><span style="color: #0000BB">mssql_query</span><span style="color: #007700">(</span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
     If attacker submits the value
     <code class="literal">a%&#039; exec master..xp_cmdshell &#039;net user test testpass /ADD&#039; --</code>
     to <var class="varname">$prod</var>, then the <var class="varname">$query</var> will be:
     <div class="informalexample">
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$query  </span><span style="color: #007700">= </span><span style="color: #DD0000">"SELECT * FROM products<br />           WHERE id LIKE '%a%'<br />           exec master..xp_cmdshell 'net user test testpass /ADD' --%'"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$result </span><span style="color: #007700">= </span><span style="color: #0000BB">mssql_query</span><span style="color: #007700">(</span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
     MSSQL Server executes the SQL statements in the batch including a command
     to add a new user to the local accounts database. If this application
     were running as <code class="literal">sa</code> and the MSSQLSERVER service was
     running with sufficient privileges, the attacker would now have an
     account with which to access this machine.
    </p>
    <blockquote class="note"><p><strong class="note">Note</strong>: 
     <p class="para">
      Some examples above are tied to a specific database server, but it
      does not mean that a similar attack is impossible against other products.
      Your database server may be similarly vulnerable in another manner.
     </p>
    </p></blockquote>
    <p class="para">
     <div class="mediaobject">
      
      <div class="imageobject">
       <img src="images/fa7c5b5f326e3c4a6cc9db19e7edbaf0-xkcd-bobby-tables.png" alt="A funny example of the issues regarding SQL injection" width="666" height="205" />
      </div>
      <div class="caption">
       <p class="simpara">
        Image courtesy of <a href="http://xkcd.com/327" class="link external">&raquo;&nbsp;xkcd</a>
       </p>
      </div>
     </div>
    </p>

    <div class="sect2" id="security.database.avoiding">
     <h3 class="title">Avoidance Techniques</h3>
     <p class="para">
      The recommended way to avoid SQL injection is by binding all data via
      prepared statements. Using parameterized queries isn&#039;t enough to entirely
      avoid SQL injection, but it is the easiest and safest way to provide input
      to SQL statements. All dynamic data literals in <code class="literal">WHERE</code>,
      <code class="literal">SET</code>, and <code class="literal">VALUES</code> clauses must be
      replaced with placeholders. The actual data will be bound during the
      execution and sent separately from the SQL command.
     </p>
     <p class="para">
      Parameter binding can only be used for data. Other dynamic parts of the
      SQL query must be filtered against a known list of allowed values.
     </p>
     <p class="para">
      <div class="example" id="example-5">
      <p><strong>Example #5 Avoiding SQL injection by using PDO prepared statements</strong></p>
       <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">// The dynamic SQL part is validated against expected values<br /></span><span style="color: #0000BB">$sortingOrder </span><span style="color: #007700">= </span><span style="color: #0000BB">$_GET</span><span style="color: #007700">[</span><span style="color: #DD0000">'sortingOrder'</span><span style="color: #007700">] === </span><span style="color: #DD0000">'DESC' </span><span style="color: #007700">? </span><span style="color: #DD0000">'DESC' </span><span style="color: #007700">: </span><span style="color: #DD0000">'ASC'</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$productId </span><span style="color: #007700">= </span><span style="color: #0000BB">$_GET</span><span style="color: #007700">[</span><span style="color: #DD0000">'productId'</span><span style="color: #007700">];<br /></span><span style="color: #FF8000">// The SQL is prepared with a placeholder<br /></span><span style="color: #0000BB">$stmt </span><span style="color: #007700">= </span><span style="color: #0000BB">$pdo</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">prepare</span><span style="color: #007700">(</span><span style="color: #DD0000">"SELECT * FROM products WHERE id LIKE ? ORDER BY price </span><span style="color: #007700">{</span><span style="color: #0000BB">$sortingOrder</span><span style="color: #007700">}</span><span style="color: #DD0000">"</span><span style="color: #007700">);<br /></span><span style="color: #FF8000">// The value is provided with LIKE wildcards<br /></span><span style="color: #0000BB">$stmt</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">execute</span><span style="color: #007700">([</span><span style="color: #DD0000">"%</span><span style="color: #007700">{</span><span style="color: #0000BB">$productId</span><span style="color: #007700">}</span><span style="color: #DD0000">%"</span><span style="color: #007700">]);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
       </div>

      </div>
     </p>

     <p class="simpara">
      Prepared statements are provided
      <a href="pdo.prepared-statements.php" class="link">by PDO</a>,
      <a href="mysqli.quickstart.prepared-statements.php" class="link">by MySQLi</a>,
      and by other database libraries.
     </p>

     <p class="simpara">
      SQL injection attacks are mainly based on exploiting the code not being written
      with security in mind. Never trust any input, especially
      from the client side, even though it comes from a select box,
      a hidden input field, or a cookie. The first example shows that such a
      simple query can cause disasters.
     </p>

     <p class="para">
      A defense-in-depth strategy involves several good coding practices:
      <ul class="itemizedlist">
       <li class="listitem">
        <span class="simpara">
         Never connect to the database as a superuser or as the database owner.
         Use always customized users with minimal privileges.
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         Check if the given input has the expected data type. <abbr title="PHP: Hypertext Preprocessor">PHP</abbr> has
         a wide range of input validating functions, from the simplest ones
         found in <a href="ref.var.php" class="link">Variable Functions</a> and
         in <a href="ref.ctype.php" class="link">Character Type Functions</a>
         (e.g. <span class="function"><a href="function.is-numeric.php" class="function">is_numeric()</a></span>, <span class="function"><a href="function.ctype-digit.php" class="function">ctype_digit()</a></span>
         respectively) and onwards to the
         <a href="ref.pcre.php" class="link">Perl Compatible Regular Expressions</a>
         support.
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         If the application expects numerical input, consider verifying data
         with <span class="function"><a href="function.ctype-digit.php" class="function">ctype_digit()</a></span>, silently change its type
         using <span class="function"><a href="function.settype.php" class="function">settype()</a></span>, or use its numeric representation
         by <span class="function"><a href="function.sprintf.php" class="function">sprintf()</a></span>.
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         If the database layer doesn&#039;t support binding variables then
         quote each non-numeric user-supplied value that is passed to the
         database with the database-specific string escape function (e.g.
         <span class="function"><a href="function.mysql-real-escape-string.php" class="function">mysql_real_escape_string()</a></span>,
         <span class="function"><strong>sqlite_escape_string()</strong></span>, etc.).
         Generic functions like <span class="function"><a href="function.addslashes.php" class="function">addslashes()</a></span> are useful only
         in a very specific environment (e.g. MySQL in a single-byte character
         set with disabled <var class="varname">NO_BACKSLASH_ESCAPES</var>), so it is
         better to avoid them.
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         Do not print out any database-specific information, especially
         about the schema, by fair means or foul. See also <a href="security.errors.php" class="link">Error Reporting</a> and <a href="ref.errorfunc.php" class="link">Error Handling and Logging Functions</a>.
        </span>
       </li>
      </ul>
     </p>

     <p class="simpara">
      Besides these, you benefit from logging queries either within your script
      or by the database itself, if it supports logging. Obviously, the logging is unable
      to prevent any harmful attempt, but it can be helpful to trace back which
      application has been circumvented. The log is not useful by itself but
      through the information it contains. More detail is generally better than less.
     </p>
    </div>
   </div><?php manual_footer($setup); ?>