There are many outstanding ways to secure applications against SQL-injections, for example this Q&A shows some ways How to prevent SQL injection in PHP?.
有许多优秀的方法可以保护应用程序不受SQL注入的影响,例如这个问答展示了如何在PHP中防止SQL注入的一些方法。
This question is about an already written application. We don't want to modify it in order to improve its safety. We want to know that the used method is vulnerable to injection attacks or not.
这个问题是关于一个已经写好的应用程序。我们不想为了提高它的安全性而修改它。我们想知道使用的方法是否容易受到注入攻击。
We need to know that this part of the code is the reason of leaking the data or not?
我们需要知道这部分代码是否是泄露数据的原因?
Here is a PHP function to eliminate some useless (for us) and maybe harmful characters:
这里有一个PHP函数,可以消除一些无用的(对我们来说)和可能有害的字符:
function removeBadCharacters($s)
{
return str_replace(array('&','<','>','/','\\','"',"'",'?','+'), '', $s);
}
It throws out dangerous characters to avoid SQL injection attack (Don't worry about removed characters such as &<>/\"'?+
the application don't need them):
它抛出危险的字符以避免SQL注入攻击(不要担心删除的字符,比如&<>/\“?+应用不需要):
$x = removeBadCharacters($_POST['data']);
mysql_query("insert into table (x) values ('".$x."');");
mysql_query("select * from into where name = '".$x."';");
-
Is it enough to make the queries secure?
是否足以保证查询的安全性?
-
Is there any way to bypass
removeBadCharacters
?有什么方法可以绕过删除字符吗?
-
How it can be broken?
它是如何被打破的?
4 个解决方案
#1
9
To be able to inject arbitrary SQL from the context of a string literal, that string literal needs to be left. This is only possible by introducing a string end delimiter, in this case a single '
, or by expand the a string literal to a preceding '
, e.g., by using the escapes character \
:
为了能够从字符串文字的上下文中注入任意的SQL,该字符串文字需要保留。这只能通过引入字符串结束分隔符(在本例中为单个')或将字符串字面量扩展到前面的'来实现,例如,使用转义字符\:
$a = '\\';
$b = ' OR 1=1 OR ';
$c = ' --';
$query = "SELECT * FROM t1 WHERE a='$a' AND b='$b' AND c='$c'";
// result:
// SELECT * FROM t1 WHERE a='\' AND b=' OR 1=1 OR ' AND c=' --'
// \_________/ \_______/
Now as your function removes any '
and \
, it seems to be impossible to leave or expand the string literal and thus not possible to inject arbitrary SQL.
现在,当您的函数删除任何“和\”时,似乎不可能离开或扩展字符串文字,因此不可能注入任意SQL。
However, since your function does not take the actual character encoding into account, it is possible to exploit this if the MySQL’s character encoding is GBK, similar to how it can be exploited when using addslashes
instead of mysql_real_escape_string
:
但是,由于您的函数没有考虑实际的字符编码,所以如果MySQL的字符编码是GBK,那么可以利用这个特性,类似于使用addslash而不是mysql_real_escape_string时的使用:
$a = "\xbf";
$b = " OR 1=1 OR ";
$c = " --";
$query = "SELECT * FROM t1 WHERE a='$a' AND b='$b' AND c='$c'";
// result:
// SELECT * FROM t1 WHERE a='縗 AND b=' OR 1=1 OR ' AND c=' --'
// \_________/ \_______/
So to play safe, use mysql_real_escape_string
or other proven methods to prevent SQL injections.
为了安全起见,使用mysql_real_escape_string或其他经过验证的方法来防止SQL注入。
#2
5
The very idea of removing whatever characters is utterly wrong.
That's what essentially wrong your approach.
这就是你的方法本质上的错误之处。
You have to format your SQL literals properly instead of spoiling them.
您必须正确地格式化SQL文字,而不是破坏它们。
Imagine this very site were using such a "protection": you'd were unable to post your question!
想象一下这个网站正在使用这样的“保护”:你无法发布你的问题!
To answer your question literally - yes, under some circumstances it's very easy to inject. Just because the very idea of all-in-once sanitization is broken. PHP had a similar feature once, called "magic quotes". It was a hard lesson, but now it's got removed from the language at last. For the very reasons I told you:
从字面上回答你的问题——是的,在某些情况下很容易注入。正因为“一劳永逸”的想法被打破了。PHP曾经有一个类似的特性,叫做“魔术引语”。这是一个艰难的教训,但现在它终于被从语言中删除了。因为我告诉你的原因
- it does not make "data" "secure"
- 它不会使"数据" "安全"
- it spoils your data instead
- 相反,它会破坏数据
Every SQL literal have to be treated personally, according to its role.
根据其角色,每个SQL文字都必须亲自处理。
#3
2
Yes, this can be defeated using Unicode characters and manipulating character sets.
是的,这可以通过使用Unicode字符和操作字符集来克服。
See https://security.stackexchange.com/questions/11391/how-did-anonymous-use-utf-16-ascii-to-fool-php-escaping for further details.
详细信息请参见https://security.stackexchange.com/questions/11391/how-did-anonymous-use-utf-16- asciito - be -php- escape。
#4
2
Your function doesn't deal with different encodings.
函数不处理不同的编码。
Don't try to come up with sanitation methods yourself, use something already made. In the case of mysql_*
, it would be mysql_real_escape_string
, however, you shouldn't use mysql_*
anymore, use PDO or mysqli instead.
不要自己想出卫生方法,用一些已经做好的东西。对于mysql_*,它将是mysql_real_escape_string,但是,您不应该再使用mysql_*,而是使用PDO或mysqli。
See: How can I prevent SQL injection in PHP? for further details.
参见:如何防止PHP中的SQL注入?为进一步的细节。
#1
9
To be able to inject arbitrary SQL from the context of a string literal, that string literal needs to be left. This is only possible by introducing a string end delimiter, in this case a single '
, or by expand the a string literal to a preceding '
, e.g., by using the escapes character \
:
为了能够从字符串文字的上下文中注入任意的SQL,该字符串文字需要保留。这只能通过引入字符串结束分隔符(在本例中为单个')或将字符串字面量扩展到前面的'来实现,例如,使用转义字符\:
$a = '\\';
$b = ' OR 1=1 OR ';
$c = ' --';
$query = "SELECT * FROM t1 WHERE a='$a' AND b='$b' AND c='$c'";
// result:
// SELECT * FROM t1 WHERE a='\' AND b=' OR 1=1 OR ' AND c=' --'
// \_________/ \_______/
Now as your function removes any '
and \
, it seems to be impossible to leave or expand the string literal and thus not possible to inject arbitrary SQL.
现在,当您的函数删除任何“和\”时,似乎不可能离开或扩展字符串文字,因此不可能注入任意SQL。
However, since your function does not take the actual character encoding into account, it is possible to exploit this if the MySQL’s character encoding is GBK, similar to how it can be exploited when using addslashes
instead of mysql_real_escape_string
:
但是,由于您的函数没有考虑实际的字符编码,所以如果MySQL的字符编码是GBK,那么可以利用这个特性,类似于使用addslash而不是mysql_real_escape_string时的使用:
$a = "\xbf";
$b = " OR 1=1 OR ";
$c = " --";
$query = "SELECT * FROM t1 WHERE a='$a' AND b='$b' AND c='$c'";
// result:
// SELECT * FROM t1 WHERE a='縗 AND b=' OR 1=1 OR ' AND c=' --'
// \_________/ \_______/
So to play safe, use mysql_real_escape_string
or other proven methods to prevent SQL injections.
为了安全起见,使用mysql_real_escape_string或其他经过验证的方法来防止SQL注入。
#2
5
The very idea of removing whatever characters is utterly wrong.
That's what essentially wrong your approach.
这就是你的方法本质上的错误之处。
You have to format your SQL literals properly instead of spoiling them.
您必须正确地格式化SQL文字,而不是破坏它们。
Imagine this very site were using such a "protection": you'd were unable to post your question!
想象一下这个网站正在使用这样的“保护”:你无法发布你的问题!
To answer your question literally - yes, under some circumstances it's very easy to inject. Just because the very idea of all-in-once sanitization is broken. PHP had a similar feature once, called "magic quotes". It was a hard lesson, but now it's got removed from the language at last. For the very reasons I told you:
从字面上回答你的问题——是的,在某些情况下很容易注入。正因为“一劳永逸”的想法被打破了。PHP曾经有一个类似的特性,叫做“魔术引语”。这是一个艰难的教训,但现在它终于被从语言中删除了。因为我告诉你的原因
- it does not make "data" "secure"
- 它不会使"数据" "安全"
- it spoils your data instead
- 相反,它会破坏数据
Every SQL literal have to be treated personally, according to its role.
根据其角色,每个SQL文字都必须亲自处理。
#3
2
Yes, this can be defeated using Unicode characters and manipulating character sets.
是的,这可以通过使用Unicode字符和操作字符集来克服。
See https://security.stackexchange.com/questions/11391/how-did-anonymous-use-utf-16-ascii-to-fool-php-escaping for further details.
详细信息请参见https://security.stackexchange.com/questions/11391/how-did-anonymous-use-utf-16- asciito - be -php- escape。
#4
2
Your function doesn't deal with different encodings.
函数不处理不同的编码。
Don't try to come up with sanitation methods yourself, use something already made. In the case of mysql_*
, it would be mysql_real_escape_string
, however, you shouldn't use mysql_*
anymore, use PDO or mysqli instead.
不要自己想出卫生方法,用一些已经做好的东西。对于mysql_*,它将是mysql_real_escape_string,但是,您不应该再使用mysql_*,而是使用PDO或mysqli。
See: How can I prevent SQL injection in PHP? for further details.
参见:如何防止PHP中的SQL注入?为进一步的细节。