8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

MySQL 8.4 参考手册 / 8 安全 / 8.1 一般安全问题 / 8.1.7 客户端编程安全指南
中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

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

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

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

访问 MySQL 的应用程序不应信任用户输入的任何数据,用户可能会试图通过在 Web 表单、URL 或您构建的任何应用程序中输入特殊或转义字符序列来欺骗您的代码。确保您的应用程序在用户尝试通过在表单中输入类似 ; DROP DATABASE mysql; 的内容进行 SQL 注入攻击时仍然是安全的。这是一个极端的例子,但如果不加防范,黑客使用类似技术可能会导致严重的安全漏洞和数据丢失。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. 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. 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.

一个常见的错误是只保护字符串数据值。记得也要检查数字数据。如果应用程序在用户输入值 234 时生成查询,例如 SELECT * FROM table WHERE ID=234,用户可以输入 234 OR 1=1 来使应用程序生成查询 SELECT * FROM table WHERE ID=234 OR 1=1。结果,服务器会检索表中的每一行。这会暴露所有行并导致服务器负载过高。防止这种类型攻击的最简单方法是在数字常量周围使用单引号:SELECT * FROM table WHERE ID='234'。如果用户输入额外信息,这些都将成为字符串的一部分。在数字上下文中,MySQL 会自动将该字符串转换为数字,并去掉其后面的非数字字符。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. As 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'. 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.

有时人们认为,如果一个数据库只包含公开可用的数据,就不需要保护。这是错误的。即使显示数据库中的任何行是允许的,你仍然应该防范拒绝服务攻击(例如,基于前一段中提到的技术导致服务器浪费资源的攻击)。否则,你的服务器将无法响应合法用户的请求。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:

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

  • 尝试在你所有的 Web 表单中输入单引号和双引号(' 和 ")。如果出现任何类型的 MySQL 错误,请立即调查问题。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.

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

  • 尝试使用前面示例中显示的字符,将动态 URL 中的数据类型从数字更改为字符类型。您的应用程序应能防御这些及类似的攻击。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.

  • 尝试在数字字段中输入字符、空格和特殊符号,而不是数字。您的应用程序应在将数据传递给 MySQL 之前将其移除,否则应生成错误。将未经检查的值传递给 MySQL 是非常危险的!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 之前,请检查数据的大小。Check the size of data before passing it to 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 语句:使用 SQL 预处理语句,并且仅通过占位符接收数据值;参见第 15.5 节,“预处理语句”。MySQL SQL statements: Use SQL prepared statements and accept data values only by means of placeholders; see Section 15.5, “Prepared Statements”.

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

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

  • PHP:使用 mysqli 或 pdo_mysql 扩展,而不要使用较旧的 ext/mysql 扩展。推荐的 API 支持改进的 MySQL 认证协议和密码,以及带占位符的预处理语句。另请参见 MySQL 和 PHP。PHP: Use either the mysqli or pdo_mysql extensions, and not the older ext/mysql extension. The preferred API's support the improved MySQL authentication protocol and passwords, as well as prepared statements with placeholders. See also MySQL and PHP.

    如果必须使用较旧的 ext/mysql 扩展,那么在转义时应使用 mysql_real_escape_string_quote() 函数,而不是 mysql_escape_string() 或 addslashes(),因为只有 mysql_real_escape_string_quote() 能识别字符集;使用(无效的)多字节字符集时,其他函数可能会被 “绕过”。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.

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

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

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

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

拦截因在 MySQL 数据库服务器上执行 SQL 语句而发生的错误,并适当处理它们,是应用程序的责任。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 错误中返回的信息并非无谓,因为这些信息在使用应用程序调试 MySQL 时至关重要。例如,几乎不可能在不提供涉及哪些数据库、表和其他对象涉及问题的信息的情况下,调试常见的 10 路连接 SELECT 语句,而不提供涉及哪些数据库、表和其他对象的问题信息。因此,MySQL 错误有时必须包含对这些对象名称的引用。The information returned in a MySQL error is not gratuitous because that information is key in debugging MySQL using applications. 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. Thus, MySQL errors must sometimes necessarily contain references to the names of those objects.

当应用程序收到 MySQL 错误时,一种简单但不安全的方法是拦截该错误并逐字显示给客户端。然而,揭示错误信息是已知的应用漏洞类型(CWE-209),应用开发者必须确保应用不存在该漏洞。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. 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.

例如,一个显示此类消息的应用程序会向客户端暴露数据库名称和表名称,这些信息可能会被客户端尝试利用: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

相反,当应用程序从 MySQL 接收到这样的错误时,正确的做法是将适当的信息,包括错误信息,记录到只有受信人员才能访问的安全审计位置。应用程序可以向用户返回更通用的内容,例如“内部错误”。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. The application can return something more generic such as “Internal Error” to the user.