访问 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.11 节,“服务器 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++:对查询流使用
escape
andquote
修饰符。PHP:使用
mysqli
或pdo_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 数据库服务器执行 SQL 语句而发生的错误并适当地处理它们。
MySQL 错误中返回的信息不是无偿的,因为该信息是使用应用程序调试 MySQL 的关键。SELECT
例如,如果不提供有关哪些数据库、表和其他对象出现问题的信息,则几乎不可能调试一个常见的 10 路连接语句。因此,MySQL 错误有时必须包含对这些对象名称的引用。
当应用程序从 MySQL 收到此类错误时,一种简单但不安全的方法是拦截它并将其逐字显示给客户端。但是,泄露错误信息是一种已知的应用程序漏洞类型 ( CWE-209 ),应用程序开发人员必须确保应用程序不存在此漏洞。
例如,显示如下消息的应用程序会向客户端公开数据库名称和表名称,这是客户端可能试图利用的信息:
ERROR 1146 (42S02): Table 'mydb.mytable' doesn't exist
相反,应用程序在从 MySQL 收到此类错误时的正确行为是将适当的信息(包括错误信息)记录到只有受信任人员才能访问的安全审计位置。应用程序可以向用户返回更通用的内容,例如“内部错误”。