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_charset
。 SET NAMES ...
不足以防止这种特定的漏洞,如果您使用受影响的MySQL版本(在5.0.22 5.0.77之前)。
是。 如果你不会忘记:
- 使用
mysql_real_rescape_string()
转义string数据 - 将数字明确地转换为数字(即:
$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的使用会很突出像一个拇指疼痛。
但是,这远远不足以确保您不易受到远程攻击:如果您通过GET
或POST
请求传递&admin=1
来表示某人是pipe理员,则您的每个用户都可以轻松升级其权限用两三秒钟的努力。 请注意,这个问题并不总是如此明显:)但这是解释信任用户提供的input太多后果的简单方法。
您应该考虑使用预处理语句/参数化查询。 这个想法是,你给占位符查询数据库。 然后给数据库你的数据,并告诉它用哪个数据replace哪个占位符,数据库确保它是有效的,并且不允许它占据占位符(即它不能结束当前查询,然后添加它自己 – 一个普通的攻击)。