Php 为什么mysql_real_escape_string()不应该';不能避免任何SQL注入吗?
我听到人们说(关于C#/SQL Server,也关于PHP/MySql):不要手动转义字符串,而是使用存储过程 好的,我可以接受这个建议,但是为什么呢?很多人说(包括这样说)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()会失败的情况?至少
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,我会在