gerzson Fri Jan 18 12:25:26 2002 EDT Modified files: /phpdoc/en/chapters security.xml Log: revise database.security section remove bla-bla note that attack examples are not database server specific
Index: phpdoc/en/chapters/security.xml diff -u phpdoc/en/chapters/security.xml:1.40 phpdoc/en/chapters/security.xml:1.41 --- phpdoc/en/chapters/security.xml:1.40 Wed Jan 16 05:09:37 2002 +++ phpdoc/en/chapters/security.xml Fri Jan 18 12:25:26 2002 @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="iso-8859-1"?> -<!-- $Revision: 1.40 $ --> +<!-- $Revision: 1.41 $ --> <chapter id="security"> <title>Security</title> @@ -117,7 +117,7 @@ </simpara> <simpara> When invoked as a CGI binary, PHP refuses to interpret the - command line arguments. + command line arguments. </simpara> </listitem> <listitem> @@ -184,7 +184,7 @@ Action directives (see below). </simpara> </sect2> - + <sect2 id="security.cgi-bin.force-redirect"> <title>Case 2: using --enable-force-cgi-redirect</title> <simpara> @@ -214,7 +214,7 @@ here. </simpara> </sect2> - + <sect2 id="security.cgi-bin.doc-root"> <title>Case 3: setting doc_root or user_dir</title> <simpara> @@ -256,7 +256,7 @@ called <filename role="uri">~user/doc.php</filename> under doc_root (yes, a directory name starting with a tilde [<literal>~</literal>]). - </simpara> + </simpara> <simpara> If user_dir is set to for example <filename role="dir">public_php</filename>, a request like <filename @@ -274,7 +274,7 @@ separately. </simpara> </sect2> - + <sect2 id="security.cgi-bin.shell"> <title>Case 4: PHP parser outside of web tree</title> <para> @@ -305,7 +305,7 @@ configure option. </para> </sect2> - + </sect1> <sect1 id="security.apache"> @@ -344,7 +344,7 @@ those who are not security professionals. </simpara> <simpara> - There are some simpler solutions. By using + There are some simpler solutions. By using <link linkend="ini.open-basedir">open_basedir</link> 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, @@ -413,7 +413,7 @@ ?> ]]> </programlisting> - </example> + </example> There are two important measures you should take to prevent these issues. <itemizedlist> @@ -435,7 +435,7 @@ <![CDATA[ <?php // removes a file from the hard drive that -// the PHP user has access to. +// the PHP user has access to. $username = $HTTP_SERVER_VARS['REMOTE_USER']; // using an authentication mechanisim $homedir = "/home/$username"; @@ -467,14 +467,14 @@ if (!ereg('^[^./][^/]*$', $userfile)) die('bad filename'); //die, do not process - + if (!ereg('^[^./][^/]*$', $username)) - die('bad username'); //die, do not process + die('bad username'); //die, do not process //etc... ?> ]]> </programlisting> - </example> + </example> </para> <para> Depending on your operating system, there are a wide variety of files @@ -483,7 +483,7 @@ well known file storage areas (/home/, My Documents), etc. For this reason, it's usually easier to create a policy where you forbid everything except for what you explicitly allow. - </para> + </para> </sect1> <sect1 id="security.database"> @@ -496,13 +496,6 @@ consider to protect them somehow. </simpara> <simpara> - PHP can be treated as a bridge between the database and client. Your script - processes the client's request, and propagates it in such manner that the - database can provide the appropriate response. After that, the script - generates its output from the supplied data, probably based on customizeable - user preferences stored in database, too. - </simpara> - <simpara> 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 @@ -583,10 +576,10 @@ </simpara> <simpara> Once an attacker gains access to your database directly (bypassing the - webserver), the sensitive data stored in it may be exposed or misused, - unless the information is protected by the database itself. Encrypting - the data is a good way to mitigate this threat, but very few databases - offer this type of data encryption. + webserver), the stored sensitive data may be exposed or misused unless, + the information is protected by the database itself. Encrypting the data + is a good way to mitigate this threat, but very few databases offer this + type of data encryption. </simpara> <simpara> The easiest way to work around this problem is to first create your own @@ -594,15 +587,15 @@ can assist you in this case with its several extensions, such as <link linkend="ref.mcrypt">Mcrypt</link> and <link linkend="ref.mhash">Mhash</link>, covering a wide variety of encryption - algorithms. The script encrypts the data be stored first, and decrypts - it when retrieving. See the references for further examples how + algorithms. The script encrypts the data be stored first, and decrypts + it when retrieving. See the references for further examples how encryption works. </simpara> <simpara> - In case of truly hidden data, if its raw representation is not needed + In case of truly hidden data, if its raw representation is not needed (i.e. not be displayed), hashing may be also taken into consideration. - The well-known example for the hashing is storing the MD5 hash of a - password in a database, instead of the password itself. See also + The well-known example for the hashing is storing the MD5 hash of a + password in a database, instead of the password itself. See also <function>crypt</function> and <function>md5</function>. </simpara> <example> @@ -621,7 +614,7 @@ if (pg_numrows($result) > 0) { echo "Wellcome, $username!"; -} +} else { echo "Authentication failed for $username."; } @@ -633,7 +626,7 @@ <sect2 id="security.database.sql-injection"> <title>SQL Injection</title> <simpara> - Many web applications are unaware of how SQL queries can be tampered with, + Many web developers are unaware of how SQL queries can be tampered with, and assume that an SQL query is a trusted command. It means that SQL queries are able to circumvent access controls, thereby bypassing standard authentication and authorization checks, and sometimes SQL queries even @@ -655,7 +648,10 @@ behalf of a superuser or the owner who can create users, the attacker may create a superuser in your database. <example> - <title>Splitting the result set into pages - and making superusers</title> + <title> + Splitting the result set into pages ... and making superusers + (PostgreSQL and MySQL) + </title> <programlisting role="php"> <![CDATA[ $offset = argv[0]; // beware, no input validation! @@ -664,11 +660,11 @@ ]]> </programlisting> </example> - Normal users click on the 'next', 'prev' links where the offset is - appended to the URL. The script expects that the incoming - <varname>$offset</varname> is numeric. However, if someone tries to + Normal users click on the 'next', 'prev' links where the +<varname>$offset</varname> + is encoded into the URL. The script expects that the incoming + <varname>$offset</varname> is decimal number. However, someone tries to break in with appending <function>urlencode</function>'d form of the - following to the URL: + following to the URL (PostgreSQL): <informalexample> <programlisting> <![CDATA[ @@ -679,7 +675,7 @@ ]]> </programlisting> </informalexample> - or + or more precisely: <informalexample> <programlisting> <![CDATA[ @@ -691,9 +687,19 @@ ]]> </programlisting> </informalexample> - then the script will present a superuser access to him. Note that - <literal>0;</literal> is to supply a valid offset to the original - query and to terminate it. + or in case of using MySQL: + <informalexample> + <programlisting> +<![CDATA[ +0; +UPDATE user SET Password=PASSWORD('crack') WHERE user='root'; +FLUSH PRIVILEGES; +]]> + </programlisting> + </informalexample> + If it happened, then the script would present a superuser access to him. + Note that <literal>0;</literal> is to supply a valid offset to the + original query and to terminate it. </para> <note> <para> @@ -705,7 +711,9 @@ <para> A feasible way to gain passwords: <example> - <title>Listing out articles - and some passwords</title> + <title> + Listing out articles ... and some passwords (any database server) + </title> <programlisting role="php"> <![CDATA[ $query = "SELECT id, name, inserted, size FROM products WHERE size = '$size';"; @@ -725,9 +733,11 @@ <literal>'</literal>), the query beast awakened. </para> <para> - SQL updates are also subject to attacking your database. + SQL UPDATEs are also subject to attacking your database. <example> - <title>From resetting a password to gaining more privileges</title> + <title> + From resetting a password ... to gaining more privileges (any database server) + </title> <programlisting role="php"> <![CDATA[ $query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';"; @@ -760,7 +770,7 @@ A frightening example how operating system level commands can be accessed on some database hosts. <example> - <title>Attacking the database host's operating system</title> + <title>Attacking the database host's operating system (MSSQL Server)</title> <programlisting role="php"> <![CDATA[ $query = "SELECT * FROM products WHERE id LIKE '%$prod%'"; @@ -769,12 +779,12 @@ </programlisting> </example> If attacker submits the value - <literal>%' exec master..xp_cmdshell 'net user test testpass /ADD' --</literal> + <literal>a%' exec master..xp_cmdshell 'net user test testpass /ADD' --</literal> to <varname>$prod</varname>, then the <varname>$query</varname> will be: <informalexample> <programlisting role="php"> <![CDATA[ -$query = "SELECT * FROM products WHERE id LIKE '%%' exec master..xp_cmdshell 'net user test testpass /ADD'--"; +$query = "SELECT * FROM products WHERE id LIKE '%a%' exec master..xp_cmdshell 'net +user test testpass /ADD'--"; $result = mssql_query($query); ]]> </programlisting> @@ -785,6 +795,13 @@ running with sufficient privileges, the attacker would now have an account with which to access this machine. </para> + <note> + <para> + Some of the examples above is tied to a specific database server. This + does not mean that a similar attack is impossible against other products. + Your database server may be so vulnerable in other manner. + </para> + </note> <sect3 id="security.database.avoiding"> <title>Avoiding techniques</title> @@ -806,26 +823,26 @@ </simpara> <itemizedlist> - <listitem> - <simpara> - First, 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 - <link linkend="ref.pcre">Perl compatible Regular Expressions</link> - support. - </simpara> - </listitem> - <listitem> - <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>. - <example> - <title>A more secure way to compose a query for paging</title> - <programlisting role="php"> + <listitem> + <simpara> + First, 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 + <link linkend="ref.pcre">Perl compatible Regular Expressions</link> + support. + </simpara> + </listitem> + <listitem> + <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>. + <example> + <title>A more secure way to compose a query for paging</title> + <programlisting role="php"> <![CDATA[ settype($order, 'integer'); $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;"; @@ -833,43 +850,43 @@ // please note %d in the format string, using %s would be meaningless $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;", $offset); ]]> - </programlisting> - </example> - </para> - </listitem> - <listitem> - <simpara> - Quote user input which is passed to the database with - <function>addslashes</function> or <function>addcslashes</function>. - See <link linkend="security.database.storage">this example</link>. - As the examples shows, quotes burnt into the static part of the query - is not enough, and can be easily hacked. - </simpara> - </listitem> - <listitem> - <simpara> - Do not print out any database specific information, especially - about the schema, no matter what happens. See also <link - linkend="security.errors">Error Reporting</link> and <link - linkend="ref.errorfunc">Error Handling and Logging Functions</link>. - </simpara> - </listitem> - <listitem> - <simpara> - You may use stored procedures and previously defined cursors to abstract - data access so that users do not directly access tables or views, but - this solution has another impacts. - </simpara> - </listitem> - </itemizedlist> + </programlisting> + </example> + </para> + </listitem> + <listitem> + <simpara> + Quote user input which is passed to the database with + <function>addslashes</function> or <function>addcslashes</function>. + See <link linkend="security.database.storage">this example</link>. + As the examples shows, quotes burnt into the static part of the query + is not enough, and can be easily hacked. + </simpara> + </listitem> + <listitem> + <simpara> + Do not print out any database specific information, especially + about the schema, no matter what happens. See also <link + linkend="security.errors">Error Reporting</link> and <link + linkend="ref.errorfunc">Error Handling and Logging Functions</link>. + </simpara> + </listitem> + <listitem> + <simpara> + You may use stored procedures and previously defined cursors to abstract + data access so that users do not directly access tables or views, but + this solution has another impacts. + </simpara> + </listitem> + </itemizedlist> - <simpara> - Besides these, you benefit from logging queries either within your script - or by the database itself, if it supports. 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. The more detail is generally better. - </simpara> + <simpara> + Besides these, you benefit from logging queries either within your script + or by the database itself, if it supports. 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. The more detail is generally better. + </simpara> </sect3> </sect2> </sect1> @@ -898,7 +915,7 @@ </form> ]]> </programlisting> - </example> + </example> </para> <para> The PHP errors which are normally returned can be quite helpful to a @@ -906,10 +923,10 @@ as the function or file that failed, the PHP file it failed in, and the line number which the failure occured in. This is all information that can be exploited. It is not uncommon for a php - developer to use <function>show_source</function>, - <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, + developer to use <function>show_source</function>, + <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. Especially dangerous is running code from known sources with built-in debugging handlers, or using common debugging techniques. If the attacker can determine what @@ -926,7 +943,7 @@ </form> ]]> </programlisting> - </example> + </example> </para> <para> Regardless of the method of error handling, the ability to probe a @@ -980,7 +997,7 @@ <![CDATA[ <?php if ($username) { // Not initialized or checked before usage - $good_login = 1; + $good_login = 1; } if ($good_login == 1) { // If above test fails, not initialized or checked before usage fpassthru ("/highly/sensitive/data/index.html"); @@ -995,9 +1012,9 @@ <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 + 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 @@ -1014,7 +1031,7 @@ <![CDATA[ <?php if ($username) { // can be forged by a user in get/post/cookies - $good_login = 1; + $good_login = 1; } if ($good_login == 1) { // can be forged by a user in get/post/cookies, @@ -1029,7 +1046,7 @@ <programlisting role="php"> <![CDATA[ <?php -if($HTTP_COOKIE_VARS['username']){ +if($HTTP_COOKIE_VARS['username']){ // can only come from a cookie, forged or otherwise $good_login = 1; fpassthru ("/highly/sensitive/data/index.html"); @@ -1052,7 +1069,7 @@ <?php if ($HTTP_COOKIE_VARS['username'] && !$HTTP_POST_VARS['username'] && - !$HTTP_GET_VARS['username'] ) { + !$HTTP_GET_VARS['username'] ) { // Perform other checks to validate the user name... $good_login = 1; fpassthru ("/highly/sensitive/data/index.html"); @@ -1071,7 +1088,7 @@ </para> </sect1> - + <sect1 id="security.variables"> <title>User Submitted Data</title> <para> @@ -1124,7 +1141,7 @@ Can this be used in conjunction with other scripts in a negative manner? </simpara> - </listitem> + </listitem> <listitem> <simpara> Will any transactions be adequately logged? @@ -1147,7 +1164,7 @@ operated upon). </para> </sect1> - + <sect1 id="security.hiding"> <title>Hiding PHP</title> <para> @@ -1162,7 +1179,7 @@ </para> <para> Another tactic is to configure web servers such as apache to - parse different filetypes through PHP, either with an .htaccess + parse different filetypes through PHP, either with an .htaccess directive, or in the apache configuration file itself. You can then use misleading file extensions: <example> @@ -1200,7 +1217,7 @@ obscurity, it's a minor preventative measure with few drawbacks. </para> </sect1> - + <sect1 id="security.current"> <title>Keeping Current</title> <simpara>