我正在使用replaceAll
根据同事的建议用"\\\\'"
替换单引号,但我很确定这不足以阻止所有SQL注入。
我做了一些谷歌搜索,发现了这个:http://wiki.postgresql.org/wiki/8.1.4_et._al._Security_Release_Technical_Info
这解释了PostgreSQL,但替换不适用于所有SQL管理器吗? (例如,MySQL,例如?)
另外,我想我理解我链接的解释是如何用于单反斜杠的,但它是否扩展到我使用四个反斜杠的情况?
请注意我对数据库及其解析输入的方式不是很熟悉,但这是我学习更多内容的机会!任何见解都将不胜感激。
编辑:我已经得到了一些非常有用,有用的答案。我的下一个问题是,什么样的输入会破坏我的实现?也就是说,如果你给我输入并且我在前面添加了四个反斜杠的单引号,你会给我什么样的输入来注入SQL代码?虽然我确信我的方法是天真和错误的,但也许一些例子会更好地教我如何轻松地将SQL注入“预防”。
答案 0 :(得分:2)
这还不够,这不是要走的路。我甚至不知道你的数据,SQL甚至是关于你的应用程序的任何信息。您永远不应该将任何用户数据直接包含在SQL中。您应该使用parameterized statements代替。
此外,如果你问这个问题,你不应该首先手工编写自己的SQL。请改用ORM。询问你的本地正则表达式是否会使你的应用程序不受SQL注入的影响,就像询问你用汇编语言编写的本地内存分配例程是否可以避免缓冲区溢出 - 我会说:如果你问的话这个问题那么你应该首先使用一种记忆安全的语言。
答案 1 :(得分:2)
不,因为反斜杠怎么样?例如,如果您将'
转换为\'
,则输入\'
将变为\\'
,这是未转义的单引号和“字符文字”反斜杠。对于mysql,每个平台都应该存在mysql_real_escape_string()
,因为它在MySQL库绑定中。
但还有另一个问题。那就是如果数据段周围没有引号。在php中,这看起来像:
$query="select * from user where id=".$_GET[id];
PoC漏洞利用非常简单:http://localhost/vuln.php?id=sleep(10)
即使您执行mysql_real_escape_string($_GET[id])
仍然容易受到sqli攻击,因为攻击者无需突破引号以执行sql。最佳解决方案是参数化查询。
答案 2 :(得分:1)
一个简单的SQL注入案例就像这样(在伪代码中):
name = form_params["name"]
year = 2011
sql = "INSERT INTO Students (name, year) " +
"VALUES ('" + name + "', " + year + ");"
database_handle.query(sql)
year
由您(程序员)提供,因此它没有被污染,并且可以以您认为合适的任何方式嵌入查询中;在这种情况下 - 作为一个不带引号的数字。
但name
由用户提供,因此可以是任何内容。顺着Bobby Tables来输入这个值:
name = "Robert'); DROP TABLE Students; -- "
查询变为
INSERT INTO Students (name, year) VALUES ('Robert');
DROP TABLE Students; -- ', 2011);
该替换将您的一个查询转换为两个。
第一个由于行计数不匹配而产生错误,但这无关紧要,因为数据库能够明确地查找并运行第二个查询。攻击者无论如何都可以通过摆弄输入来解决错误。 --
是注释,因此忽略输入的其余部分。
请注意数据突然变成代码 - 这是安全问题的典型标志。
建议的替代品的作用是:
name = form_params["name"].regex_replace("'", "\\\\'")
这是如何起作用的,因此我早先的评论。字符串文字"\\\\'"
表示字符串\\'
。 regex_replace
函数将其解释为字符串\'
。然后数据库看到
... VALUES ('Robert\'); DROP TABLE Students; -- ', 2011);
并正确地将其解释为一个非常不寻常的名字。
在其他问题中,这种方法非常脆弱。如果您在语言中使用的字符串不会将\\
替换为\
,那么如果您的字符串替换函数未将\\
解释为\
(如果它不是正则表达式)函数或它使用$1
代替\1
进行反向引用)你最终会得到偶数个斜杠,如
... VALUES ('Robert\\'); DROP TABLE Students; -- ', 2011);
和没有将阻止SQL注入。
解决方案不是检查语言和库对您可以想到的所有可能输入的作用,或者预测它在未来版本中可能做什么,而是使用数据库提供的功能。这些通常有两种形式:
数据库感知转义,它完全正确地转义任何数据,因为客户端库与服务器匹配,并且它知道您要查询的数据库的字符编码是:
sql = "... '" + database_handle.escape(name) + "' ..."
带外数据提交(通常带有准备好的声明),因此数据甚至与代码不在同一个字符串中:
sql = "... VALUES (:n, :y);"
database_handle.query(sql, n = name, y = year)