我们都知道我们应该使用预准备语句或适当的替换/格式化规则,以防止在我们的应用程序中注入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 )这个查询?
答案 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)
您的问题中有两个错误的陈述会导致您混淆:
- 我们都知道我们应该使用......相应的替换规则,以防止在我们的应用程序中注入sql。
醇>
这是错误的陈述。不是替换,而是格式化。这是必不可少的。格式化时,替换不能防止注入。请注意,查询的每个不同部分都需要不同的格式,这对任何其他部分都无用。比如,还有另一个角色,对于注射保护至关重要 - 一个反击(`)。但是你没有列出它,因为它与字符串文字无关。
- '(单引号),\(反斜杠)和“(双引号)都需要转义以防止注入
醇>
这是非常错误的陈述。 转义不会阻止注入!这些字符需要转义才能格式化字符串,并且与注入完全无关。虽然正确格式化的查询部分确实对注入是无懈可击的。但事实是 - 你必须为了它而格式化动态查询部分,遵循语法规则 - 而不是因为任何注入。因此,您的查询将无法穿透。
现在你可以看到为什么你的上一个陈述,
为什么所有这些其他角色都足够脆弱,可以通过mysql_real_escape_string进行转义,因为它对我来说并不是很明显。
错误地说:
字符串格式化规则需要这些字符,而不是“漏洞”。其中一些是为了方便而转义,一些是为了可读性,一些是为了逃避分隔符的明显原因。就是这样。
回答评论中的最新问题:
我真的想要一个答案,因为PHP的mysql_real_escape_string也没有引用这些文字。
再次说明:尽管普通PHP用户mysql_real_escape_string()
与任何惊吓注入密切相关,但实际上却没有。没有“危险”字符。不是一个人。有一些具有特殊含义的服务字符。他们必须在某些情况下逃脱,取决于具体情况。
因此,此功能逃脱的角色与“危险”无关。当你开始认为mysql_real_escape_string()
的目的是逃避“危险”角色时,你确实处于危险之中。只要您使用此函数只是为了逃避字符串(并无条件地执行它) - 您可能认为自己是安全的(当然如果您不忘记格式化所有其他文字,使用它们各自的格式化规则)
我想知道“%”字符是否可以导致LIKE子句中的额外结果。
没有