6.1.7 Client Programming Security Guidelines客户端编程安全指南

Client applications that access MySQL should use the following guidelines to avoid interpreting external data incorrectly or exposing sensitive information.访问MySQL的客户端应用程序应使用以下准则,以避免错误地解释外部数据或暴露敏感信息。

Handle External Data Properly正确处理外部数据

Applications that access MySQL should not trust any data entered by users, who can try to trick your code by entering special or escaped character sequences in Web forms, URLs, or whatever application you have built. 访问MySQL的应用程序不应信任用户输入的任何数据,用户可以通过在Web表单、URL或您构建的任何应用程序中输入特殊或转义字符序列来欺骗您的代码。Be sure that your application remains secure if a user tries to perform SQL injection by entering something like ; DROP DATABASE mysql; into a form. 如果用户试图通过输入以下内容; DROP DATABASE mysql;进入表单来执行SQL注入,请确保您的应用程序保持安全。This is an extreme example, but large security leaks and data loss might occur as a result of hackers using similar techniques, if you do not prepare for them.这是一个极端的例子,但如果你不做好准备,黑客使用类似的技术可能会导致大规模的安全漏洞和数据丢失。

A common mistake is to protect only string data values. Remember to check numeric data as well. 一个常见的错误是只保护字符串数据值。记住还要检查数字数据。If an application generates a query such as SELECT * FROM table WHERE ID=234 when a user enters the value 234, the user can enter the value 234 OR 1=1 to cause the application to generate the query SELECT * FROM table WHERE ID=234 OR 1=1. 如果当用户输入值234时,应用程序生成诸如SELECT * FROM table WHERE ID=234的查询,则用户可以输入值234 OR 1=1,以使应用程序生成查询SELECT * FROM table WHERE ID=234 OR 1=1As a result, the server retrieves every row in the table. 因此,服务器检索表中的每一行。This exposes every row and causes excessive server load. The simplest way to protect from this type of attack is to use single quotation marks around the numeric constants: SELECT * FROM table WHERE ID='234'. 这会暴露每一行,并导致服务器负载过重。防止此类攻击的最简单方法是在数字常量周围使用单引号:SELECT * FROM table WHERE ID='234'If the user enters extra information, it all becomes part of the string. In a numeric context, MySQL automatically converts this string to a number and strips any trailing nonnumeric characters from it.如果用户输入了额外的信息,这些信息都会成为字符串的一部分。在数字上下文中,MySQL会自动将此字符串转换为数字,并从中删除任何尾随的非数字字符。

Sometimes people think that if a database contains only publicly available data, it need not be protected. This is incorrect. 有时人们认为,如果数据库只包含公开可用的数据,就不需要保护。这是不正确的。Even if it is permissible to display any row in the database, you should still protect against denial of service attacks (for example, those that are based on the technique in the preceding paragraph that causes the server to waste resources). Otherwise, your server becomes unresponsive to legitimate users.即使允许显示数据库中的任何行,您仍然应该防止拒绝服务攻击(例如,基于上一段中导致服务器浪费资源的技术的攻击)。否则,您的服务器将对合法用户没有响应。

Checklist:

  • Enable strict SQL mode to tell the server to be more restrictive of what data values it accepts. See Section 5.1.11, “Server SQL Modes”.启用严格的SQL模式,告诉服务器对它接受的数据值有更严格的限制。请参阅第5.1.11节,“服务器SQL模式”

  • Try to enter single and double quotation marks (' and ") in all of your Web forms. If you get any kind of MySQL error, investigate the problem right away.尝试在所有Web表单中输入单引号和双引号('")。如果您遇到任何MySQL错误,请立即调查问题。

  • Try to modify dynamic URLs by adding %22 ("), %23 (#), and %27 (') to them.尝试通过向动态URL添加%22")、%23#)和%27')来修改它们。

  • Try to modify data types in dynamic URLs from numeric to character types using the characters shown in the previous examples. Your application should be safe against these and similar attacks.尝试使用前面示例中显示的字符将动态URL中的数据类型从数字类型修改为字符类型。您的应用程序应该能够安全地抵御这些和类似的攻击。

  • Try to enter characters, spaces, and special symbols rather than numbers in numeric fields. Your application should remove them before passing them to MySQL or else generate an error. Passing unchecked values to MySQL is very dangerous!尝试在数字字段中输入字符、空格和特殊符号,而不是数字。你的应用程序应该在将它们传递给MySQL之前删除它们,否则会产生错误。将未经检查的值传递给MySQL是非常危险的!

  • Check the size of data before passing it to MySQL.在将数据传递给MySQL之前,请检查数据的大小。

  • Have your application connect to the database using a user name different from the one you use for administrative purposes. Do not give your applications any access privileges they do not need.让您的应用程序使用与用于管理目的的用户名不同的用户名连接到数据库。不要给你的应用程序任何他们不需要的访问权限。

Many application programming interfaces provide a means of escaping special characters in data values. Properly used, this prevents application users from entering values that cause the application to generate statements that have a different effect than you intend:许多应用程序编程接口提供了一种转义数据值中特殊字符的方法。如果使用得当,这可以防止应用程序用户输入导致应用程序生成与您预期效果不同的语句的值:

  • MySQL SQL statements: Use SQL prepared statements and accept data values only by means of placeholders; see Section 13.5, “Prepared Statements”.MySQL SQL语句:使用SQL编写的语句,仅通过占位符接受数据值;参阅第13.5节,“Prepared语句”

  • MySQL C API: Use the mysql_real_escape_string_quote() API call. 使用mysql_real_cescape_string_quote()API调用。Alternatively, use the C API prepared statement interface and accept data values only by means of placeholders; see C API Prepared Statement Interface.或者,使用C API准备的语句接口,仅通过占位符接受数据值;请参见C API准备的语句接口

  • MySQL++: Use the escape and quote modifiers for query streams.对查询流使用escapequote修饰符。

  • PHP: Use either the mysqli or pdo_mysql extensions, and not the older ext/mysql extension. 使用mysqlipdo_mysql扩展,而不是旧的ext/mysql扩展。The preferred API's support the improved MySQL authentication protocol and passwords, as well as prepared statements with placeholders. 首选的API支持改进的MySQL身份验证协议和密码,以及带有占位符的准备语句。See also Choosing an API.另请参见选择API

    If the older ext/mysql extension must be used, then for escaping use the mysql_real_escape_string_quote() function and not mysql_escape_string() or addslashes() because only mysql_real_escape_string_quote() is character set-aware; the other functions can be bypassed when using (invalid) multibyte character sets.如果必须使用较旧的ext/mysql扩展名,那么对于转义,请使用mysql_real_escape_string_quote()函数,而不是mysql_escape_string()addslashes(),因为只有mysql_real_escape_string_quote()是字符集感知的;使用(无效)多字节字符集时,可以“绕过”其他函数。

  • Perl DBI: Use placeholders or the quote() method.使用占位符或quote()方法。

  • Ruby DBI: Use placeholders or the quote() method.使用占位符或quote()方法。

  • Java JDBC: Use a PreparedStatement object and placeholders.使用PreparedStatement对象和占位符。

Other programming interfaces might have similar capabilities.其他编程接口可能具有类似的功能。

Handle MySQL Error Messages Properly正确处理MySQL错误消息

It is the application's responsibility to intercept errors that occur as a result of executing SQL statements with the MySQL database server and handle them appropriately.应用程序有责任拦截MySQL数据库服务器执行SQL语句时发生的错误,并对其进行适当处理。

The information returned in a MySQL error is not gratuitous because that information is key in debugging MySQL using applications. MySQL错误中返回的信息不是无偿的,因为这些信息是使用应用程序调试MySQL的关键。It would be nearly impossible, for example, to debug a common 10-way join SELECT statement without providing information regarding which databases, tables, and other objects are involved with problems.例如,在不提供有关哪些数据库、表和其他对象涉及问题的信息的情况下,调试一个常见的10路连接SELECT语句几乎是不可能的。 Thus, MySQL errors must sometimes necessarily contain references to the names of those objects.因此,MySQL错误有时必须包含对这些对象名称的引用。

A simple but insecure approach for an application when it receives such an error from MySQL is to intercept it and display it verbatim to the client. 当应用程序从MySQL收到此类错误时,一种简单但不安全的方法是拦截它并将其逐字显示给客户端。However, revealing error information is a known application vulnerability type (CWE-209) and the application developer must ensure the application does not have this vulnerability.然而,泄露错误信息是一种已知的应用程序漏洞类型(CWE-209),应用程序开发人员必须确保应用程序没有此漏洞。

For example, an application that displays a message such as this exposes both a database name and a table name to clients, which is information a client might attempt to exploit:例如,显示此类消息的应用程序向客户端公开数据库名称和表名称,这是客户端可能试图利用的信息:

ERROR 1146 (42S02): Table 'mydb.mytable' doesn't exist

Instead, the proper behavior for an application when it receives such an error from MySQL is to log appropriate information, including the error information, to a secure audit location only accessible to trusted personnel.相反,当应用程序从MySQL收到此类错误时,其正确的行为是将包括错误信息在内的适当信息记录到仅可由受信任人员访问的安全审计位置。 The application can return something more generic such as Internal Error to the user.应用程序可以向用户返回更通用的内容,如“内部错误”。