访问 MySQL 的客户端应用程序应使用以下指南,以避免错误地解释外部数据或泄露敏感信息。
访问 MySQL 的应用程序不应信任用户输入的任何数据,用户可能会尝试通过在 Web 表单、URL 或您构建的任何应用程序中输入特殊或转义字符序列来欺骗您的代码。如果用户试图通过在表单中输入类似 ; DROP DATABASE mysql;
的内容来执行 SQL 注入,请确保您的应用程序仍然安全。这是一个极端的例子,但如果您不做好准备,黑客使用类似的技术可能会导致大规模的安全漏洞和数据丢失。
一个常见的错误是只保护字符串数据值。请记住也要检查数字数据。如果应用程序在用户输入值 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 会自动将此字符串转换为数字,并从中删除任何尾随的非数字字符。
有时人们认为,如果数据库只包含公开可用的数据,就不需要保护它。这是不正确的。即使允许显示数据库中的任何行,您仍然应该防止拒绝服务攻击(例如,那些基于上一段中导致服务器浪费资源的技术)。否则,您的服务器将无法响应合法用户。
检查表
启用严格 SQL 模式,告诉服务器对它接受的数据值更加严格。请参阅 第 7.1.11 节“服务器 SQL 模式”。
尝试在所有 Web 表单中输入单引号和双引号(
'
和"
)。如果您收到任何类型的 MySQL 错误,请立即调查问题。尝试通过向动态 URL 添加
%22
("
)、%23
(#
) 和%27
('
) 来修改它们。尝试使用前面示例中显示的字符将动态 URL 中的数据类型从数字类型修改为字符类型。您的应用程序应该能够抵御这些攻击和类似的攻击。
尝试在数字字段中输入字符、空格和特殊符号,而不是数字。您的应用程序应该在将它们传递给 MySQL 之前删除它们,否则会生成错误。将未经检查的值传递给 MySQL 是非常危险的!
在将数据传递给 MySQL 之前,请检查数据的大小。
让您的应用程序使用与您用于管理目的不同的用户名连接到数据库。不要给您的应用程序任何它们不需要的访问权限。
许多应用程序编程接口提供了一种转义数据值中特殊字符的方法。如果使用得当,这可以防止应用程序用户输入导致应用程序生成与您预期效果不同的语句的值。
MySQL SQL 语句:使用 SQL 预处理语句,并且只通过占位符接受数据值;请参阅 第 15.5 节“预处理语句”。
MySQL C API:使用
mysql_real_escape_string_quote()
API 调用。或者,使用 C API 预处理语句接口,并仅通过占位符接受数据值;请参阅C API 预处理语句接口。MySQL++:对查询流使用
escape
和quote
修饰符。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 时至关重要的。例如,如果不提供有关哪些数据库、表和其他对象与问题相关的信息,几乎不可能调试常见的 10 路连接 SELECT
语句。因此,MySQL 错误有时必须包含对这些对象名称的引用。
当应用程序收到来自 MySQL 的此类错误时,一种简单但不安全的方法是拦截它并将其逐字显示给客户端。但是,泄露错误信息是一种已知的应用程序漏洞类型 (CWE-209),应用程序开发人员必须确保应用程序没有此漏洞。
例如,显示如下消息的应用程序会将数据库名称和表名都暴露给客户端,而客户端可能会尝试利用这些信息
ERROR 1146 (42S02): Table 'mydb.mytable' doesn't exist
相反,当应用程序收到来自 MySQL 的此类错误时,正确的行为是将适当的信息(包括错误信息)记录到只有受信任人员才能访问的安全审计位置。应用程序可以向用户返回更通用的内容,例如““内部错误””。