From 56fb691746801add7d65811954c40c1a493f35b8 Mon Sep 17 00:00:00 2001 From: Gyozo Papp Date: Fri, 18 Jan 2002 17:25:26 +0000 Subject: [PATCH] revise database.security section remove bla-bla note that attack examples are not database server specific git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@68050 c90b9560-bf6c-de11-be94-00142212c4b1 --- chapters/security.xml | 259 ++++++++++++++++++++++-------------------- security/index.xml | 259 ++++++++++++++++++++++-------------------- 2 files changed, 276 insertions(+), 242 deletions(-) diff --git a/chapters/security.xml b/chapters/security.xml index 3a88bb5074..9cc294c998 100644 --- a/chapters/security.xml +++ b/chapters/security.xml @@ -1,5 +1,5 @@ - + Security @@ -117,7 +117,7 @@ When invoked as a CGI binary, PHP refuses to interpret the - command line arguments. + command line arguments. @@ -184,7 +184,7 @@ Action directives (see below). - + Case 2: using --enable-force-cgi-redirect @@ -214,7 +214,7 @@ AddHandler php-script .php here. - + Case 3: setting doc_root or user_dir @@ -256,7 +256,7 @@ AddHandler php-script .php called ~user/doc.php under doc_root (yes, a directory name starting with a tilde [~]). - + If user_dir is set to for example public_php, a request like - + Case 4: PHP parser outside of web tree @@ -305,7 +305,7 @@ AddHandler php-script .php configure option. - + @@ -344,7 +344,7 @@ AddHandler php-script .php those who are not security professionals. - There are some simpler solutions. By using + There are some simpler solutions. By using open_basedir 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 @@ echo "/home/../etc/passwd has been deleted!"; ?> ]]> - + There are two important measures you should take to prevent these issues. @@ -435,7 +435,7 @@ echo "/home/../etc/passwd has been deleted!"; ]]> - + Depending on your operating system, there are a wide variety of files @@ -483,7 +483,7 @@ if (!ereg('^[^./][^/]*$', $username)) 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. - + @@ -495,13 +495,6 @@ if (!ereg('^[^./][^/]*$', $username)) or secret informations can be stored in such database, you should strongly consider to protect them somehow. - - 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. - 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. @@ -583,10 +576,10 @@ if (!ereg('^[^./][^/]*$', $username)) 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. The easiest way to work around this problem is to first create your own @@ -594,15 +587,15 @@ if (!ereg('^[^./][^/]*$', $username)) can assist you in this case with its several extensions, such as Mcrypt and Mhash, 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. - 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 crypt and md5. @@ -621,7 +614,7 @@ $result = pg_exec($connection, $query); if (pg_numrows($result) > 0) { echo "Wellcome, $username!"; -} +} else { echo "Authentication failed for $username."; } @@ -633,7 +626,7 @@ else { SQL Injection - 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 @@ else { behalf of a superuser or the owner who can create users, the attacker may create a superuser in your database. - Splitting the result set into pages - and making superusers + + Splitting the result set into pages ... and making superusers + (PostgreSQL and MySQL) + - Normal users click on the 'next', 'prev' links where the offset is - appended to the URL. The script expects that the incoming - $offset is numeric. However, if someone tries to + Normal users click on the 'next', 'prev' links where the $offset + is encoded into the URL. The script expects that the incoming + $offset is decimal number. However, someone tries to break in with appending urlencode'd form of the - following to the URL: + following to the URL (PostgreSQL): - or + or more precisely: - then the script will present a superuser access to him. Note that - 0; is to supply a valid offset to the original - query and to terminate it. + or in case of using MySQL: + + + + + + If it happened, then the script would present a superuser access to him. + Note that 0; is to supply a valid offset to the + original query and to terminate it. @@ -705,7 +711,9 @@ insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) A feasible way to gain passwords: - Listing out articles - and some passwords + + Listing out articles ... and some passwords (any database server) + '), the query beast awakened. - SQL updates are also subject to attacking your database. + SQL UPDATEs are also subject to attacking your database. - From resetting a password to gaining more privileges + + From resetting a password ... to gaining more privileges (any database server) + - Attacking the database host's operating system + Attacking the database host's operating system (MSSQL Server) If attacker submits the value - %' exec master..xp_cmdshell 'net user test testpass /ADD' -- + a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- to $prod, then the $query will be: @@ -785,6 +795,13 @@ $result = mssql_query($query); running with sufficient privileges, the attacker would now have an account with which to access this machine. + + + 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. + + Avoiding techniques @@ -806,26 +823,26 @@ $result = mssql_query($query); - - - 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 Variable Functions and - in Character Type Functions - sections, (e.g. is_numeric, - ctype_digit respectively) onwards the - Perl compatible Regular Expressions - support. - - - - - If the application waits for numeric input, consider to verify data - with is_numeric, or silently change its type - using settype or sprintf(). - - A more secure way to compose a query for paging - + + + 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 Variable Functions and + in Character Type Functions + sections, (e.g. is_numeric, + ctype_digit respectively) onwards the + Perl compatible Regular Expressions + support. + + + + + If the application waits for numeric input, consider to verify data + with is_numeric, or silently change its type + using settype or sprintf(). + + A more secure way to compose a query for paging + - - - - - - - Quote user input which is passed to the database with - addslashes or addcslashes. - See this example. - As the examples shows, quotes burnt into the static part of the query - is not enough, and can be easily hacked. - - - - - Do not print out any database specific information, especially - about the schema, no matter what happens. See also Error Reporting and Error Handling and Logging Functions. - - - - - 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. - - - + + + + + + + Quote user input which is passed to the database with + addslashes or addcslashes. + See this example. + As the examples shows, quotes burnt into the static part of the query + is not enough, and can be easily hacked. + + + + + Do not print out any database specific information, especially + about the schema, no matter what happens. See also Error Reporting and Error Handling and Logging Functions. + + + + + 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. + + + - - 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. - + + 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. + @@ -898,7 +915,7 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % ]]> - + The PHP errors which are normally returned can be quite helpful to a @@ -906,10 +923,10 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % 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 show_source, - highlight_string, or - highlight_file as a debugging measure, but in - a live site, this can expose hidden variables, unchecked syntax, + developer to use show_source, + highlight_string, or + highlight_file 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 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % ]]> - + Regardless of the method of error handling, the ability to probe a @@ -980,7 +997,7 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % Using Register Globals - 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 + 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 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 @@ if ($good_login == 1) { // If above test fails, not initialized or checked befor - + User Submitted Data @@ -1124,7 +1141,7 @@ exec ($evil_var); Can this be used in conjunction with other scripts in a negative manner? - + Will any transactions be adequately logged? @@ -1147,7 +1164,7 @@ exec ($evil_var); operated upon). - + Hiding PHP @@ -1162,7 +1179,7 @@ exec ($evil_var); 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: @@ -1200,7 +1217,7 @@ AddType application/x-httpd-php .htm .html obscurity, it's a minor preventative measure with few drawbacks. - + Keeping Current diff --git a/security/index.xml b/security/index.xml index 3a88bb5074..9cc294c998 100644 --- a/security/index.xml +++ b/security/index.xml @@ -1,5 +1,5 @@ - + Security @@ -117,7 +117,7 @@ When invoked as a CGI binary, PHP refuses to interpret the - command line arguments. + command line arguments. @@ -184,7 +184,7 @@ Action directives (see below). - + Case 2: using --enable-force-cgi-redirect @@ -214,7 +214,7 @@ AddHandler php-script .php here. - + Case 3: setting doc_root or user_dir @@ -256,7 +256,7 @@ AddHandler php-script .php called ~user/doc.php under doc_root (yes, a directory name starting with a tilde [~]). - + If user_dir is set to for example public_php, a request like - + Case 4: PHP parser outside of web tree @@ -305,7 +305,7 @@ AddHandler php-script .php configure option. - + @@ -344,7 +344,7 @@ AddHandler php-script .php those who are not security professionals. - There are some simpler solutions. By using + There are some simpler solutions. By using open_basedir 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 @@ echo "/home/../etc/passwd has been deleted!"; ?> ]]> - + There are two important measures you should take to prevent these issues. @@ -435,7 +435,7 @@ echo "/home/../etc/passwd has been deleted!"; ]]> - + Depending on your operating system, there are a wide variety of files @@ -483,7 +483,7 @@ if (!ereg('^[^./][^/]*$', $username)) 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. - + @@ -495,13 +495,6 @@ if (!ereg('^[^./][^/]*$', $username)) or secret informations can be stored in such database, you should strongly consider to protect them somehow. - - 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. - 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. @@ -583,10 +576,10 @@ if (!ereg('^[^./][^/]*$', $username)) 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. The easiest way to work around this problem is to first create your own @@ -594,15 +587,15 @@ if (!ereg('^[^./][^/]*$', $username)) can assist you in this case with its several extensions, such as Mcrypt and Mhash, 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. - 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 crypt and md5. @@ -621,7 +614,7 @@ $result = pg_exec($connection, $query); if (pg_numrows($result) > 0) { echo "Wellcome, $username!"; -} +} else { echo "Authentication failed for $username."; } @@ -633,7 +626,7 @@ else { SQL Injection - 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 @@ else { behalf of a superuser or the owner who can create users, the attacker may create a superuser in your database. - Splitting the result set into pages - and making superusers + + Splitting the result set into pages ... and making superusers + (PostgreSQL and MySQL) + - Normal users click on the 'next', 'prev' links where the offset is - appended to the URL. The script expects that the incoming - $offset is numeric. However, if someone tries to + Normal users click on the 'next', 'prev' links where the $offset + is encoded into the URL. The script expects that the incoming + $offset is decimal number. However, someone tries to break in with appending urlencode'd form of the - following to the URL: + following to the URL (PostgreSQL): - or + or more precisely: - then the script will present a superuser access to him. Note that - 0; is to supply a valid offset to the original - query and to terminate it. + or in case of using MySQL: + + + + + + If it happened, then the script would present a superuser access to him. + Note that 0; is to supply a valid offset to the + original query and to terminate it. @@ -705,7 +711,9 @@ insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) A feasible way to gain passwords: - Listing out articles - and some passwords + + Listing out articles ... and some passwords (any database server) + '), the query beast awakened. - SQL updates are also subject to attacking your database. + SQL UPDATEs are also subject to attacking your database. - From resetting a password to gaining more privileges + + From resetting a password ... to gaining more privileges (any database server) + - Attacking the database host's operating system + Attacking the database host's operating system (MSSQL Server) If attacker submits the value - %' exec master..xp_cmdshell 'net user test testpass /ADD' -- + a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- to $prod, then the $query will be: @@ -785,6 +795,13 @@ $result = mssql_query($query); running with sufficient privileges, the attacker would now have an account with which to access this machine. + + + 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. + + Avoiding techniques @@ -806,26 +823,26 @@ $result = mssql_query($query); - - - 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 Variable Functions and - in Character Type Functions - sections, (e.g. is_numeric, - ctype_digit respectively) onwards the - Perl compatible Regular Expressions - support. - - - - - If the application waits for numeric input, consider to verify data - with is_numeric, or silently change its type - using settype or sprintf(). - - A more secure way to compose a query for paging - + + + 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 Variable Functions and + in Character Type Functions + sections, (e.g. is_numeric, + ctype_digit respectively) onwards the + Perl compatible Regular Expressions + support. + + + + + If the application waits for numeric input, consider to verify data + with is_numeric, or silently change its type + using settype or sprintf(). + + A more secure way to compose a query for paging + - - - - - - - Quote user input which is passed to the database with - addslashes or addcslashes. - See this example. - As the examples shows, quotes burnt into the static part of the query - is not enough, and can be easily hacked. - - - - - Do not print out any database specific information, especially - about the schema, no matter what happens. See also Error Reporting and Error Handling and Logging Functions. - - - - - 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. - - - + + + + + + + Quote user input which is passed to the database with + addslashes or addcslashes. + See this example. + As the examples shows, quotes burnt into the static part of the query + is not enough, and can be easily hacked. + + + + + Do not print out any database specific information, especially + about the schema, no matter what happens. See also Error Reporting and Error Handling and Logging Functions. + + + + + 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. + + + - - 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. - + + 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. + @@ -898,7 +915,7 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % ]]> - + The PHP errors which are normally returned can be quite helpful to a @@ -906,10 +923,10 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % 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 show_source, - highlight_string, or - highlight_file as a debugging measure, but in - a live site, this can expose hidden variables, unchecked syntax, + developer to use show_source, + highlight_string, or + highlight_file 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 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % ]]> - + Regardless of the method of error handling, the ability to probe a @@ -980,7 +997,7 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET % Using Register Globals - 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 + 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 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 @@ if ($good_login == 1) { // If above test fails, not initialized or checked befor - + User Submitted Data @@ -1124,7 +1141,7 @@ exec ($evil_var); Can this be used in conjunction with other scripts in a negative manner? - + Will any transactions be adequately logged? @@ -1147,7 +1164,7 @@ exec ($evil_var); operated upon). - + Hiding PHP @@ -1162,7 +1179,7 @@ exec ($evil_var); 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: @@ -1200,7 +1217,7 @@ AddType application/x-httpd-php .htm .html obscurity, it's a minor preventative measure with few drawbacks. - + Keeping Current