MySQL 8.0 参考手册  / 第 6 章 安全  / 6.1 一般安全问题  /  6.1.7 客户端编程安全指南

6.1.7 客户端编程安全指南

访问 MySQL 的客户端应用程序应使用以下准则以避免错误解释外部数据或暴露敏感信息。

妥善处理外部数据

访问 MySQL 的应用程序不应该信任用户输入的任何数据,他们可以通过在 Web 表单、URL 或您构建的任何应用程序中输入特殊或转义字符序列来尝试欺骗您的代码。如果用户试图通过在表单中​​输入类似的内容来执行 SQL 注入,请确保您的应用程序保持安全; DROP DATABASE mysql;。这是一个极端的例子,但如果您不做好准备,黑客使用类似技术可能会导致大量安全漏洞和数据丢失。

一个常见的错误是只保护字符串数据值。记得还要检查数字数据。如果应用程序生成一个查询,例如SELECT * FROM table WHERE ID=234当用户输入值 234时,用户可以输入该值 234 OR 1=1以使应用程序生成查询SELECT * FROM table WHERE ID=234 OR 1=1。结果,服务器检索表中的每一行。这会暴露每一行并导致服务器负载过大。防止此类攻击的最简单方法是在数字常量周围使用单引号: SELECT * FROM table WHERE ID='234'. 如果用户输入额外的信息,这些信息都会成为字符串的一部分。在数字上下文中,MySQL 自动将此字符串转换为数字并从中删除任何尾随的非数字字符。

有时人们认为,如果数据库仅包含公开可用的数据,则无需保护。这是不正确的。即使允许显示数据库中的任何行,您仍然应该防止拒绝服务攻击(例如,那些基于前段技术导致服务器浪费资源的攻击)。否则,您的服务器将无法响应合法用户。

清单:

  • 启用严格的 SQL 模式以告诉服务器对其接受的数据值有更多限制。请参阅 第 5.1.10 节,“服务器 SQL 模式”

  • 尝试在所有 Web 表单中 输入单引号和双引号 ( 'and )。"如果您遇到任何类型的 MySQL 错误,请立即调查问题。

  • 尝试通过添加%22 ( ")、%23 ( #) 和%27 ( ') 来修改动态 URL。

  • 尝试使用前面示例中显示的字符将动态 URL 中的数据类型从数字修改为字符类型。您的应用程序应该能够抵御这些和类似的攻击。

  • 尝试在数字字段中输入字符、空格和特殊符号,而不是数字。您的应用程序应该在将它们传递给 MySQL 之前删除它们,否则会产生错误。将未经检查的值传递给 MySQL 是非常危险的!

  • 在将数据传递给 MySQL 之前检查数据的大小。

  • 让您的应用程序使用不同于您用于管理目的的用户名连接到数据库。不要给你的应用程序任何他们不需要的访问权限。

许多应用程序编程接口提供了一种转义数据值中特殊字符的方法。如果使用得当,这可以防止应用程序用户输入导致应用程序生成具有与您预期不同效果的语句的值:

  • MySQL SQL语句:使用SQL预处理语句,仅通过占位符方式接受数据值;参见 第 13.5 节,“准备好的语句”

  • MySQL C API:使用 mysql_real_escape_string_quote() API 调用。或者,使用 C API 准备语句接口并仅通过占位符接受数据值;请参阅 C API 准备语句接口

  • MySQL++:对查询流使用escapeand quote修饰符。

  • PHP:使用mysqlipdo_mysql扩展,而不是旧的 ext/mysql扩展。首选 API 支持改进的 MySQL 身份验证协议和密码,以及带有占位符的准备好的语句。另请参阅MySQL 和 PHP

    ext/mysql如果必须使用 旧的扩展名,那么为了转义使用mysql_real_escape_string_quote() 函数而不是 mysql_escape_string()或者 addslashes()因为只有 mysql_real_escape_string_quote() 字符集可识别;使用(无效的)多字节字符集时 可以 绕过”其他功能。

  • Perl DBI:使用占位符或quote() 方法。

  • Java JDBC:使用PreparedStatement对象和占位符。

其他编程接口可能具有类似的功能。

正确处理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.

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.

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 收到此类错误时的正确行为是将适当的信息(包括错误信息)记录到只有受信任人员才能访问的安全审计位置。应用程序可以向用户返回更通用的内容,例如内部错误