Php 为什么mysql_real_escape_string()不应该';不能避免任何SQL注入吗?

Php 为什么mysql_real_escape_string()不应该';不能避免任何SQL注入吗?,php,mysql,security,sql-injection,Php,Mysql,Security,Sql Injection,我听到人们说(关于C#/SQL Server,也关于PHP/MySql):不要手动转义字符串,而是使用存储过程 好的,我可以接受这个建议,但是为什么呢?很多人说(包括这样说)mysql\u real\u escape\u string()就足够了,mysql\u real\u escape\u string()很好,mysql\u real\u escape\u string()是第一种保护方式 为什么??是否存在mysql\u real\u escape\u string()会失败的情况?至少

我听到人们说(关于C#/SQL Server,也关于PHP/MySql):不要手动转义字符串,而是使用存储过程

好的,我可以接受这个建议,但是为什么呢?很多人说(包括这样说)
mysql\u real\u escape\u string()
就足够了,
mysql\u real\u escape\u string()
很好,
mysql\u real\u escape\u string()
是第一种保护方式

为什么??是否存在
mysql\u real\u escape\u string()
会失败的情况?至少有一个。。。我不需要太多:)

只是为了获取信息:
mysql\u real\u escape\u string()。在MySQL中,如果将这些通配符与
LIKE、GRANT或REVOKE组合使用,则会出现以下两种情况
MySQL\u real\u escape\u string

  • 你可以忘记使用它
  • 如果您正在使用某些特定的多字节连接编码,并且使用
    set NAMES
    来设置这些编码,而不是按原样设置,则仍然会使您容易受到攻击
更新:

  • 您使用UTF-8是安全的(尽管这并不意味着您应该继续使用
    集合名称
    !)
  • 有关说明,请参阅

mysql\u real\u escape\u string()
可能无法清除输入。 因为清理字符串时,
mysql\u real\u esacpe\u string()
会考虑字符集。 这就是问题所在。您可以通过
mysql\u query
函数发送查询以更改连接的字符集来更改字符。但是,
mysql\u real\u escape\u string()
对您正在使用的集合不起作用,它将不正确地转义某些字符

另一件事是不断地手动调用它。甚至将其包装到函数中也是一个P.I.T.a.,因为这意味着您必须创建自己的某种数据库包装器/数据库抽象层,以便能够自动调用
mysql\u real\u escape\u string()

这就是为什么我们在PHP中有PDO,这有助于我们缓解上述所有问题,并且您可以使用参数化的prepared语句,它们是处理改变数据的重复查询的首选方法


准备语句,绑定输入变量,它将根据正在使用的数据库驱动程序和连接的字符集清除输入。它的代码更少,而且完全安全。

当mysql\u real\u escape\u string失败时:

$sql = "SELECT * FROM users WHERE id=" + mysql_real_escape_string($_GET['id']);
如果
$\u GET['user\u id']
设置为1或1=1,则不存在特殊字符,也不会对其进行筛选

结果:返回所有行。

情况变得更糟了。这个怎么样。。。如果
$\u GET['user\u id']
被设置为1或\u admin=1,该怎么办


该函数仅设计为在单引号内使用。

mysql\u real\u escape\u string()和SQL注入只有一点-

前者与后者没有丝毫关系。

虽然听起来很矛盾,但没有什么比这更真实了

这里有两个陈述来证明这一点

  • 您只需转义带引号的字符串,因为此函数没有其他帮助
  • 事实上,您必须转义要添加到查询中的每个字符串,即使是最安全的字符串。只是因为它可能包含一些特殊字符,从而破坏了查询(就像意外事件,而不是恶意阴谋)
  • 因此,在适用的情况下,不管有什么危险或恐惧,都必须使用此函数。在任何其他情况下,这都不会有任何帮助


    我唯一要补充的是,准备好的声明也不能提供充分的保护。以下是解释和建议:

    它最大的缺点是您可能会忘记使用它!您会发现MySQL中存储过程的使用率低于SQL Server,但PHP/MySQL API通常鼓励使用预处理语句。使用MySQL\u real\u escape\u string()我从来没有遇到过任何问题。我想人们说使用存储过程是因为有可能忘记使用mysql\u real\u escape\u String()。@Tomalak Geret'kal:怎么了?@Khronos:“我从来没有遇到过问题”不算什么。对于大多数人(基本用法,没有针对你的应用程序的攻击),如果“他们有问题”,那么整个世界也会有同样的问题。这意味着在你了解什么是
    mysql\u real\u escape\u string
    之前,这个问题早就解决了。你能给我举一个第二点的例子吗?我在UTF8中使用集合名,它应该是安全的,对吗?第三件事:你可以记住使用它,在不使用引号的时候这样做。没有什么是完全安全的,即使是PDO。也就是说,它没有将表名和列名用作参数的机制,因此无论哪种方式,最终都会使用手动卫生设备来防止注射,即使使用PDO。@holodoc-如果您发现自己需要通过PDO绑定列名和表名,这意味着您从用户输入中接收列名/表名,这进一步意味着你这样做完全是错误的。否则,如果您已经将列/表编码到DBAL数组中,那么需要额外检查它们是否导致sql错误?PDO在保存用户输入方面是非常安全的。mysql\u real\u escape有一些缺陷,这些缺陷已经被指出。为什么使用动态列和表名意味着这些是从用户输入检索的?在许多情况下,表/列名是由简单的流控制确定的。@holodoc那么你关于PDO不安全的论点是没有意义的,如果你不是从用户而是从安全的来源接收输入(列、表名),为什么要使用PDO来清除输入?你的观点毫无意义,对不起。我在野外经常看到这一点是的!通常,如果我考虑int,我会在