mysql_real_escape_string()和mysql_escape_string()是否足以保证应用程序的安全性?

mysql_real_rescape_string()是否足以保护我免受黑客和SQL攻击? 问,因为我听说这些不能帮助所有的攻击媒介? 寻找专家的意见。

编辑:另外,LIKE SQL攻击呢?

@Charles是非常正确的!

您将自己置于多种已知 SQL攻击的风险之中,包括,正如您所提到的那样

  • SQL注入:是的! Mysql_Escape_String可能仍然让你容易受到SQL注入,这取决于你在查询中使用PHPvariables的位置。

考虑这个:

 $sql = "SELECT number FROM PhoneNumbers " . "WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value); 

那样可以安全和准确地逃脱吗? 没有! 为什么? 因为黑客还可以这么做:

跟着我重复:

mysql_real_escape_string()只是为了转义variables数据,而不是表名,列名,特别是不是限制字段。

  • LIKE漏洞利用:LIKE“$ data%”其中$ data可能是“%”,这将返回所有logging…这可能是一个安全漏洞…只要想象一下查找信用卡的最后四位数字。 OOP! 现在,黑客可能会收到您的系统中的每个信用卡号码! (顺便说一句:存储完整的信用卡很less推荐!)

  • Charset漏洞利用:无论仇恨者如何说,IE浏览器在2011年仍然容易受到字符集漏洞攻击,这就是说, 如果你正确地devise了你的HTML页面,那么相当于<meta name="charset" value="UTF-8"/> ! 这些攻击是非常令人讨厌的,因为它们给予黑客尽可能多的直接SQL注入控制:例如完整的。

下面是一些示例代码来演示所有这些:

 // Contains class DBConfig; database information. require_once('../.dbcreds'); $dblink = mysql_connect(DBConfig::$host, DBConfig::$user, DBConfig::$pass); mysql_select_db(DBConfig::$db); //print_r($argv); $sql = sprintf("SELECT url FROM GrabbedURLs WHERE %s LIKE '%s%%' LIMIT %s", mysql_real_escape_string($argv[1]), mysql_real_escape_string($argv[2]), mysql_real_escape_string($argv[3])); echo "SQL: $sql\n"; $qq = mysql_query($sql); while (($data = mysql_fetch_array($qq))) { print_r($data); } 

这是这个代码的结果,当各种input通过时:

 $ php sql_exploits.php url http://www.reddit.com id SQL generated: SELECT url FROM GrabbedURLs WHERE url LIKE 'http://www.reddit.com%' ORDER BY id; Returns: Just URLs beginning w/ "http://www.reddit.com" $ php sql_exploits.php url % id SQL generated: SELECT url FROM GrabbedURLs WHERE url LIKE '%%' ORDER BY id; Results: Returns every result Not what you programmed, ergo an exploit -- 

$ php sql_exploits.php 1 = 1'http://www.reddit.com'id结果:返回每列和每个结果。;

然后是非常令人讨厌的LIMIT漏洞:

 $ php sql_exploits.php url > 'http://www.reddit.com' > "UNION SELECT name FROM CachedDomains" Generated SQL: SELECT url FROM GrabbedURLs WHERE url LIKE 'http://reddit.com%' LIMIT 1 UNION SELECT name FROM CachedDomains; Returns: An entirely unexpected, potentially (probably) unauthorized query from another, completely different table. 

无论您是否了解攻击中的SQL,都是无可指摘的。 这已经certificate了,即使是最不成熟的黑客,mysql_real_escape_string()也很容易被绕过。 那是因为它是一个react native的防守机制。 它只修复数据库中非常有限和已知的漏洞。

所有转义将永远不会足以保护数据库。 事实上,你可以明确地对所有已知的漏洞做出反应,而且将来你的代码将很有可能变得容易受到未来发现的攻击。

正确的,唯一的(真的)防御是一个主动的防御:使用预先准备的语句。 已准备好的语句经过特殊处理,因此只执行有效和已编程的SQL。 这意味着,如果正确完成,可以执行的意外SQL的可能性大大降低。

理论上讲,准备好的语句不会受到所有已知和未知的攻击的影响,因为它们是SERVER SIDE技术,由DATABASE SERVERS THEMSELVES和与编程语言接口的库处理。 因此,你总是保证免受各种已知的黑客的攻击,至less。

而且代码less了:

 $pdo = new PDO($dsn); $column = 'url'; $value = 'http://www.stackoverflow.com/'; $limit = 1; $validColumns = array('url', 'last_fetched'); // Make sure to validate whether $column is a valid search parameter. // Default to 'id' if it's an invalid column. if (!in_array($column, $validColumns) { $column = 'id'; } $statement = $pdo->prepare('SELECT url FROM GrabbedURLs ' . 'WHERE ' . $column . '=? ' . 'LIMIT ' . intval($limit)); $statement->execute(array($value)); while (($data = $statement->fetch())) { } 

那现在不是那么难吗? 而且它的代码less了百分之四十七 (195个字节(PDO)vs 375个字符(mysql_),这就是我所说的“完全胜利”。

编辑:为了解决所有的争议这个答案激起了,让我重申我已经说过:

使用预先准备的语句允许人们利用SQL服务器本身的保护措施,因此可以防止SQL服务器人员知道的事情。 由于这种额外的保护水平,无论多么彻底,你都远比使用逃避安全得多。

没有!


重要更新:在testingCol Shrapnel提供的可能的利用代码并检查MySQL版本5.0.22,5.0.45,5.0.77和5.1.48之后,看起来GBK字符集和其他可能的MySQL 字符集MySQL版本如果使用SET NAMES而不是使用特定的mysql_set_charset / mysqli_set_charset函数,则5.0.77可能会使代码易受攻击。 由于这些只是在PHP 5.2.x中添加的,即使您认为自己是安全的并且一切正确,通过书籍,旧的PHP和旧的MySQL的组合也可能产生潜在的SQL注入漏洞


如果不将字符集设置为与mysql_real_escape_string结合使用,那么您可能会发现自己容易受到老版本MySQL可能利用的特定字符集的攻击。 更多信息在以前的研究 。

如果可能的话,使用mysql_set_charsetSET NAMES ...不足以防止这种特定的漏洞,如果您使用受影响的MySQL版本(在5.0.22 5.0.77之前)。

是。 如果你不会忘记:

  1. 使用mysql_real_rescape_string()转义string数据
  2. 将数字明确地转换为数字(即: $id = (int)$_GET['id'];

那么你受到保护。

我个人更喜欢准备的陈述 :

 <?php $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?"); if ($stmt->execute(array($_GET['name']))) { while ($row = $stmt->fetch()) { print_r($row); } } ?> 

忽略使用*escape_string()函数时漏掉的一个或另一个特定的variables是非常容易的,但是如果所有的查询都是准备好的语句,那么它们都是正常的,插值variables的使用会很突出像一个拇指疼痛。

但是,这远远不足以确保您不易受到远程攻击:如果您通过GETPOST请求传递&admin=1来表示某人是pipe理员,则您的每个用户都可以轻松升级其权限用两三秒钟的努力。 请注意,这个问题并不总是如此明显:)但这是解释信任用户提供的input太多后果的简单方法。

您应该考虑使用预处理语句/参数化查询。 这个想法是,你给占位符查询数据库。 然后给数据库你的数据,并告诉它用哪个数据replace哪个占位符,数据库确保它是有效的,并且不允许它占据占位符(即它不能结束当前查询,然后添加它自己 – 一个普通的攻击)。