哪些字符实际上能够在mysql中引起SQL注入

时间:2013-01-17 01:10:47

标签: mysql security escaping sql-injection

我们都知道我们应该使用预准备语句或适当的替换/格式化规则,以防止在我们的应用程序中注入sql。

但是,在查看MySQL的字符文字列表时,我注意到它包含以下字符:

  • \0 ASCII NUL(0x00)字符。
  • \'单引号(')字符。
  • \"双引号(")字符。
  • \b退格字符。
  • \n换行符(换行符)。
  • \r回车符。
  • \t标签字符。
  • \Z ASCII 26( Ctrl + Z )。见表格后面的注释。
  • \\反斜杠(\)字符。
  • \% %个字符。
  • \_ _个字符。

现在,虽然需要转义%_字符以防止将不需要的通配符注入LIKE语句,并且'(单引号),{{ 1}}(反斜杠)和\(双引号)都需要进行转义以防止注入任意SQL - 未转义的任何其他字符都可能直接导致SQL注入漏洞,否则出席?有没有人有这样一个利用的现实世界的例子?

我们假设我们正在构建我们的查询:

"

SELECT * FROM users WHERE username='$user' 是否有任何值,其中唯一未转义的字符文字是$user(退格),\b(NUL),\0(换行符),允许将任意SQL注入的\n(换行符),\r(制表符)或\t Ctrl + Z )这个查询?

2 个答案:

答案 0 :(得分:4)

考虑以下来自mysql_real_escape_string()手册的行:

  

MySQL只需要反斜杠,并且用于引用查询中字符串的引号字符将被转义。 mysql_real_escape_string()引用其他字符,以便在日志文件中更容易阅读。

单独使用这些特殊字符不应该在MySQL中进行SQL注入:\b \0 \n \r \t \Z

但是,String Literals手册说明了以下内容,但指定(或不指定)的原因与SQL注入无关:

  

如果要将二进制数据插入字符串列(例如BLOB列),则应通过转义序列表示某些字符。必须转义反斜杠(“\”)和用于引用字符串的引号字符。在某些客户端环境中,可能还需要转义NUL或Control + Z.如果未转义,mysql客户端会截断包含NUL字符的带引号的字符串,如果未转义,则可以在Windows上使用Control + Z作为END-OF-FILE。

此外,在一个简单的测试中,无论天气如何,上面列出的特殊字符都被转义,MySQL产生了相同的结果。换句话说,MySQL甚至不介意:

$query_sql = "SELECT * FROM `user` WHERE user = '$user'";

以上查询对上面列出的字符的非转义和转义版本的工作方式类似,如下所示:

$user = chr(8);     // Back Space
$user = chr(0);     // Null char
$user = chr(13);    // Carriage Return
$user = chr(9);     // Horizontal Tab
$user = chr(26);    // Substitute
$user = chr(92) .chr(8);    // Escaped Back Space
$user = chr(92) .chr(0);    // Escaped Null char
$user = chr(92) .chr(13);   // Escaped Carriage Return
$user = chr(92) .chr(9);    // Escaped Horizontal Tab
$user = chr(92) .chr(26);   // Escaped Substitute

简单测试中使用的测试表和数据:

-- Table Structure

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(10) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

-- Table Data

INSERT INTO `user` ( `user` ) VALUES
( char( '8' ) ),
( char( '0' ) ),
( char( '10' ) ),
( char( '13' ) ),
( char( '9' ) ),
( char( '26' ) );

答案 1 :(得分:3)

没有这样的人物。

您的问题中有两个错误的陈述会导致您混淆:

  
      
  1. 我们都知道我们应该使用......相应的替换规则,以防止在我们的应用程序中注入sql。
  2.   

这是错误的陈述。不是替换,而是格式化。这是必不可少的。格式化时,替换不能防止注入。请注意,查询的每个不同部分都需要不同的格式,这对任何其他部分都无用。比如,还有另一个角色,对于注射保护至关重要 - 一个反击(`)。但是你没有列出它,因为它与字符串文字无关。

  
      
  1. '(单引号),\(反斜杠)和“(双引号)都需要转义以防止注入
  2.   

这是非常错误的陈述。 转义不会阻止注入!这些字符需要转义才能格式化字符串,并且与注入完全无关。虽然正确格式化的查询部分确实对注入是无懈可击的。但事实是 - 你必须为了它而格式化动态查询部分,遵循语法规则 - 而不是因为任何注入。因此,您的查询将无法穿透。

现在你可以看到为什么你的上一个陈述,

  

为什么所有这些其他角色都足够脆弱,可以通过mysql_real_escape_string进行转义,因为它对我来说并不是很明显。

错误地说:
字符串格式化规则需要这些字符,而不是“漏洞”。其中一些是为了方便而转义,一些是为了可读性,一些是为了逃避分隔符的明显原因。就是这样。

回答评论中的最新问题:

  

我真的想要一个答案,因为PHP的mysql_real_escape_string也没有引用这些文字。

再次说明:尽管普通PHP用户mysql_real_escape_string()与任何惊吓注入密切相关,但实际上却没有。没有“危险”字符。不是一个人。有一些具有特殊含义的服务字符。他们必须在某些情况下逃脱,取决于具体情况。

因此,此功能逃脱的角色与“危险”无关。当你开始认为mysql_real_escape_string()的目的是逃避“危险”角色时,你确实处于危险之中。只要您使用此函数只是为了逃避字符串(并无条件地执行它) - 您可能认为自己是安全的(当然如果您不忘记格式化所有其他文字,使用它们各自的格式化规则)

  

我想知道“%”字符是否可以导致LIKE子句中的额外结果。

没有