mysql_real_escape_string()和mysql_escape_string()是否足以满足应用安全性?

时间:2011-03-24 04:23:24

标签: php mysql security

mysql_real_rescape_string()是否足以保护我免受黑客和SQL攻击?问,因为我听说这些对所有攻击媒介没有帮助?寻求专家的建议。

编辑:另外,LIKE SQL攻击怎么样?

5 个答案:

答案 0 :(得分:14)

@Charles是非常正确的!

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

  • SQL注入:是的! Mysql_Escape_String可能STILL使您容易受到SQL注入的影响,具体取决于您在查询中使用PHP变量的位置。

考虑一下:

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

这样可以安全准确地逃脱吗?没有!为什么?因为黑客很可能仍然这样做:

在我之后重复:

mysql_real_escape_string()仅用于转义变量数据, NOT 表名,列名,尤其不是LIMIT字段。

  • LIKE漏洞:喜欢“$ data%”,其中$ data可能是“%”,这将返回所有记录...... 很可能一个安全漏洞......只是想象一下信用卡的最后四位数的查询...... OOP!现在,黑客可能会收到您系统中的每个信用卡号码! (顺便说一句:几乎不建议存储完整的信用卡!)

  • Charset漏洞利用:无论仇恨者说什么,2011年的Internet Explorer 仍然,容易受到字符集漏洞利用的影响,而如果你已经设计您的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);
}

以下是传递各种输入时此代码的结果:

$ 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是不可取的。这表明即使是最不成熟的黑客,mysql_real_escape_string()也很容易被轻易所规避。那是因为它是一种反应性的防御机制。它只修复了数据库中非常有限且已知的漏洞。

所有转义都不足以保护数据库。实际上,您可以明确地对每个KNOWN漏洞进行REACT,并且将来,您的代码很可能会受到未来发现的攻击的攻击。<​​/ p>

正确的,唯一的(真的)辩护是主动的:使用准备好的陈述。准备好的语句经过精心设计,因此只执行有效和PROGRAMMED SQL。这意味着,如果正确完成,可以执行意外SQL的几率会大大降低。

理论上,完美实现的预处理语句将不受所有已知和未知攻击的影响,因为它们是服务器端技术,由DATABASE SERVERS THEMSELVES和与编程语言交互的库处理。因此,您始终可以保证在最低限度下保护您免受所有人的伤害。

而且代码更少:

$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())) { }

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

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

  

使用准备好的陈述可以让人们利用保护措施   SQL服务器本身,因此   你受到了保护   SQL服务器的人都知道。因为   这个额外的保护水平,你   远比使用更安全   逃避,无论多么彻底。

答案 1 :(得分:8)

没有!


重要更新:在测试possible exploit code provided by Col. Shrapnel并查看MySQL版本5.0.22,5.0.45,5.0.77和5.1.48后,似乎 GBK字符如果使用SET NAMES而不是使用mysql_set_charset具体的mysqli_set_charset / SET NAMES ...功能。因为那些仅在PHP 5.2.x中添加,旧的PHP和旧的MySQL的组合可能产生潜在的SQL注入漏洞,即使您认为自己是安全的并且正确地做了所有事情,通过 - 书。


如果没有将字符集mysql_real_escape_string结合使用,您可能会发现自己容易受到旧MySQL版本可能的特定字符集攻击。 More info on previous research

如果可能,请使用mysql_set_charset。如果您使用受影响的MySQL版本( 5.0.22 5.0.77之前),则{{1}} 足以防止此特定漏洞利用。

答案 2 :(得分:7)

是。如果你不会忘记:

  1. 使用mysql_real_rescape_string()
  2. 转义字符串数据
  3. 明确地将数字转换为数字(即:$id = (int)$_GET['id'];
  4. 然后你受到了保护。

答案 3 :(得分:3)

我个人更喜欢prepared statements

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

在使用其中一个*escape_string()函数时忽略一个或另一个特定变量很容易,但如果所有查询都是预处理语句,那么它们都很好,并且使用插值变量会像拇指一样突出。

但这远远不足以确保您不会受到远程攻击的影响:如果您通过&admin=1GET请求传递POST来表示某人是管理员,您的每个用户都可以通过两到三秒的努力轻松升级他们的权限。请注意,这个问题并不总是很明显:)但这是一种简单的方法来解释信任用户提供的输入过多的后果。

答案 4 :(得分:2)

您应该考虑使用预准备语句/参数化查询。这个想法是你给数据库一个带占位符的查询。然后,您向数据库提供数据,并告诉它哪个占位符替换为所述数据,并且数据库确保它是有效的并且不允许它超出占位符(即它不能结束当前查询然后添加它自己 - 一种常见的攻击。)