From d9d0ce4b1982dded6fbe802be7ba14f8b088e642 Mon Sep 17 00:00:00 2001 From: Gyozo Papp Date: Mon, 21 Jan 2002 14:36:58 +0000 Subject: [PATCH] better description of the SQL injection examples git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@68311 c90b9560-bf6c-de11-be94-00142212c4b1 --- chapters/security.xml | 102 +++++++++++++++++++++++------------------- security/index.xml | 102 +++++++++++++++++++++++------------------- 2 files changed, 110 insertions(+), 94 deletions(-) diff --git a/chapters/security.xml b/chapters/security.xml index 9cc294c998..62b292e930 100644 --- a/chapters/security.xml +++ b/chapters/security.xml @@ -1,5 +1,5 @@ - + Security @@ -498,8 +498,8 @@ if (!ereg('^[^./][^/]*$', $username)) To retrieve or to store any information you need to connect to the database, send a legitimate query, fetch the result, and close the connecion. - Nowadays, the commonly used interface in the interaction with databases is - the Structured Query Language (SQL). See how an attacker can tamper with an SQL query. @@ -636,16 +636,13 @@ else { Direct SQL Command Injection is a technique where an attacker creates or alters existing SQL commands to expose hidden data, or to override valuable ones, or even to execute dangerous system level commands on the database - host. - - - This is accomplished by the application taking user input and combining - it with static parameters to build a SQL query. The following examples - are based on true stories, unfortunately. + host. This is accomplished by the application taking user input and + combining it with static parameters to build a SQL query. The following + examples are based on true stories, unfortunately. Owing to the lack of input validation and connecting to the database on - behalf of a superuser or the owner who can create users, the attacker + behalf of a superuser or the one who can create users, the attacker may create a superuser in your database. @@ -657,6 +654,8 @@ else { $offset = argv[0]; // beware, no input validation! $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;"; $result = pg_exec($conn, $query); +// with MySQL: +$result = mysql_query($query); ]]> </programlisting> </example> @@ -669,17 +668,6 @@ $result = pg_exec($conn, $query); <programlisting> <![CDATA[ 0; -insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) - values ('crack', 31, 't','t','crack'); --- -]]> - </programlisting> - </informalexample> - or more precisely: - <informalexample> - <programlisting> -<![CDATA[ -0; insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) select 'crack', usesysid, 't','t','crack' from pg_shadow where usename='postgres'; @@ -709,14 +697,23 @@ FLUSH PRIVILEGES; </para> </note> <para> - A feasible way to gain passwords: + A feasible way to gain passwords is to circumvent your search result pages. + What the attacker has to do is only trying if there is a submitted filter + setting handled not properly. These filters are commonly set in a previous + form to customize <literal>WHERE, ORDER BY, LIMIT and OFFSET</literal> + clauses in <literal>SELECT</literal> statements. If your database supports + the <literal>UNION</literal> construct, the attacker may try to append an + entire query to the original one to list passwords from an arbitrary table. + Using encrypted password fields is strongly encouraged. <example> <title> Listing out articles ... and some passwords (any database server) @@ -725,15 +722,24 @@ $query = "SELECT id, name, inserted, size FROM products WHERE size = '$size';"; - If this query were assigned to $size (prepended with - '), the query beast awakened. + If this query (playing with the ' and + --) were assigned to one of the variables used in + $query, the query beast awakened. - SQL UPDATEs are also subject to attacking your database. + SQL UPDATEs are also subject to attacking your database. These queries are + also threatened by chopping and appending an entirely new query to it. But + the attacker might fiddle with the SET clause. In this + case some schema information must be possessed to manipulate the query + successfully. This can be acquired by examing the form variable names, or + just simply brute forcing. There are not so many naming convention for + fields storing passwords or usernames. From resetting a password ... to gaining more privileges (any database server) @@ -745,22 +751,16 @@ $query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';"; </programlisting> </example> But a malicious user sumbits the value - <literal>' or uid like'%admin%'; --</literal> to <varname>$uid</varname>, - and the query will be twisted: - <informalexample> - <programlisting role="php"> -<![CDATA[ -$query = "UPDATE usertable SET pwd='...' WHERE uid='' or like '%admin%'; --"; -]]> - </programlisting> - </informalexample> - Now, the admin user password has been changed. Alternatively, the attacker - simply sets <varname>$pwd</varname> to - <literal>"hehehe', admin='yes', trusted=100 </literal> (with a trailing - space) to gain more privileges: + <literal>' or uid like'%admin%'; --</literal> to <varname>$uid</varname> to + change the admin's password, or simply sets <varname>$pwd</varname> to + <literal>"hehehe', admin='yes', trusted=100 "</literal> (with a trailing + space) to gain more privileges. Then, the query will be twisted: <informalexample> <programlisting role="php"> <![CDATA[ +// $uid == ' or uid like'%admin%'; -- +$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --"; +// $pwd == "hehehe', admin='yes', trusted=100 " $query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE ...;" ]]> </programlisting> @@ -818,19 +818,26 @@ $result = mssql_query($query); <simpara> These attacks are mainly based on exploiting the code not being written with security in mind. Never trust on any kind of input, especially - which comes from the client side. The first example shows that such a + which comes 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 blameless query can cause disasters. </simpara> <itemizedlist> <listitem> <simpara> - First, check if the given input has the expected data type. PHP has + Never connect to the database as a superuser or as the database owner. + Use always customized users with very limited privileges. + </simpara> + </listitem> + <listitem> + <simpara> + Check if the given input has the expected data type. PHP has a wide range of input validating functions, from the simplest ones found in <link linkend="ref.variables">Variable Functions</link> and in <link linkend="ref.ctype">Character Type Functions</link> - sections, (e.g. <function>is_numeric</function>, - <function>ctype_digit</function> respectively) onwards the + (e.g. <function>is_numeric</function>, <function>ctype_digit</function> + respectively) onwards the <link linkend="ref.pcre">Perl compatible Regular Expressions</link> support. </simpara> @@ -839,7 +846,8 @@ $result = mssql_query($query); <para> If the application waits for numeric input, consider to verify data with <function>is_numeric</function>, or silently change its type - using <function>settype</function> or <function>sprintf()</function>. + using <function>settype</function>, or use its numeric representation + by <function>sprintf</function>. <example> <title>A more secure way to compose a query for paging @@ -856,9 +864,9 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % - Quote user input which is passed to the database with + Quote each non numeric user input which is passed to the database with addslashes or addcslashes. - See this example. + See the first example. As the examples shows, quotes burnt into the static part of the query is not enough, and can be easily hacked. diff --git a/security/index.xml b/security/index.xml index 9cc294c998..62b292e930 100644 --- a/security/index.xml +++ b/security/index.xml @@ -1,5 +1,5 @@ - + Security @@ -498,8 +498,8 @@ if (!ereg('^[^./][^/]*$', $username)) To retrieve or to store any information you need to connect to the database, send a legitimate query, fetch the result, and close the connecion. - Nowadays, the commonly used interface in the interaction with databases is - the Structured Query Language (SQL). See how an attacker can tamper with an SQL query. @@ -636,16 +636,13 @@ else { Direct SQL Command Injection is a technique where an attacker creates or alters existing SQL commands to expose hidden data, or to override valuable ones, or even to execute dangerous system level commands on the database - host. - - - This is accomplished by the application taking user input and combining - it with static parameters to build a SQL query. The following examples - are based on true stories, unfortunately. + host. This is accomplished by the application taking user input and + combining it with static parameters to build a SQL query. The following + examples are based on true stories, unfortunately. Owing to the lack of input validation and connecting to the database on - behalf of a superuser or the owner who can create users, the attacker + behalf of a superuser or the one who can create users, the attacker may create a superuser in your database. @@ -657,6 +654,8 @@ else { $offset = argv[0]; // beware, no input validation! $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;"; $result = pg_exec($conn, $query); +// with MySQL: +$result = mysql_query($query); ]]> </programlisting> </example> @@ -669,17 +668,6 @@ $result = pg_exec($conn, $query); <programlisting> <![CDATA[ 0; -insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) - values ('crack', 31, 't','t','crack'); --- -]]> - </programlisting> - </informalexample> - or more precisely: - <informalexample> - <programlisting> -<![CDATA[ -0; insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) select 'crack', usesysid, 't','t','crack' from pg_shadow where usename='postgres'; @@ -709,14 +697,23 @@ FLUSH PRIVILEGES; </para> </note> <para> - A feasible way to gain passwords: + A feasible way to gain passwords is to circumvent your search result pages. + What the attacker has to do is only trying if there is a submitted filter + setting handled not properly. These filters are commonly set in a previous + form to customize <literal>WHERE, ORDER BY, LIMIT and OFFSET</literal> + clauses in <literal>SELECT</literal> statements. If your database supports + the <literal>UNION</literal> construct, the attacker may try to append an + entire query to the original one to list passwords from an arbitrary table. + Using encrypted password fields is strongly encouraged. <example> <title> Listing out articles ... and some passwords (any database server) @@ -725,15 +722,24 @@ $query = "SELECT id, name, inserted, size FROM products WHERE size = '$size';"; - If this query were assigned to $size (prepended with - '), the query beast awakened. + If this query (playing with the ' and + --) were assigned to one of the variables used in + $query, the query beast awakened. - SQL UPDATEs are also subject to attacking your database. + SQL UPDATEs are also subject to attacking your database. These queries are + also threatened by chopping and appending an entirely new query to it. But + the attacker might fiddle with the SET clause. In this + case some schema information must be possessed to manipulate the query + successfully. This can be acquired by examing the form variable names, or + just simply brute forcing. There are not so many naming convention for + fields storing passwords or usernames. From resetting a password ... to gaining more privileges (any database server) @@ -745,22 +751,16 @@ $query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';"; </programlisting> </example> But a malicious user sumbits the value - <literal>' or uid like'%admin%'; --</literal> to <varname>$uid</varname>, - and the query will be twisted: - <informalexample> - <programlisting role="php"> -<![CDATA[ -$query = "UPDATE usertable SET pwd='...' WHERE uid='' or like '%admin%'; --"; -]]> - </programlisting> - </informalexample> - Now, the admin user password has been changed. Alternatively, the attacker - simply sets <varname>$pwd</varname> to - <literal>"hehehe', admin='yes', trusted=100 </literal> (with a trailing - space) to gain more privileges: + <literal>' or uid like'%admin%'; --</literal> to <varname>$uid</varname> to + change the admin's password, or simply sets <varname>$pwd</varname> to + <literal>"hehehe', admin='yes', trusted=100 "</literal> (with a trailing + space) to gain more privileges. Then, the query will be twisted: <informalexample> <programlisting role="php"> <![CDATA[ +// $uid == ' or uid like'%admin%'; -- +$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --"; +// $pwd == "hehehe', admin='yes', trusted=100 " $query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE ...;" ]]> </programlisting> @@ -818,19 +818,26 @@ $result = mssql_query($query); <simpara> These attacks are mainly based on exploiting the code not being written with security in mind. Never trust on any kind of input, especially - which comes from the client side. The first example shows that such a + which comes 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 blameless query can cause disasters. </simpara> <itemizedlist> <listitem> <simpara> - First, check if the given input has the expected data type. PHP has + Never connect to the database as a superuser or as the database owner. + Use always customized users with very limited privileges. + </simpara> + </listitem> + <listitem> + <simpara> + Check if the given input has the expected data type. PHP has a wide range of input validating functions, from the simplest ones found in <link linkend="ref.variables">Variable Functions</link> and in <link linkend="ref.ctype">Character Type Functions</link> - sections, (e.g. <function>is_numeric</function>, - <function>ctype_digit</function> respectively) onwards the + (e.g. <function>is_numeric</function>, <function>ctype_digit</function> + respectively) onwards the <link linkend="ref.pcre">Perl compatible Regular Expressions</link> support. </simpara> @@ -839,7 +846,8 @@ $result = mssql_query($query); <para> If the application waits for numeric input, consider to verify data with <function>is_numeric</function>, or silently change its type - using <function>settype</function> or <function>sprintf()</function>. + using <function>settype</function>, or use its numeric representation + by <function>sprintf</function>. <example> <title>A more secure way to compose a query for paging @@ -856,9 +864,9 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % - Quote user input which is passed to the database with + Quote each non numeric user input which is passed to the database with addslashes or addcslashes. - See this example. + See the first example. As the examples shows, quotes burnt into the static part of the query is not enough, and can be easily hacked.