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

Mon*_*ica 21 php mysql security

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

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

The*_*ith 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);  
Run Code Online (Sandbox Code Playgroud)

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

在我之后重复:

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

  • 喜欢利用:喜欢"$ 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);
}
Run Code Online (Sandbox Code Playgroud)

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

$ 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 --
Run Code Online (Sandbox Code Playgroud)

$ PHP sql_exploits.php 1 = 1 ' http://www.reddit.com '身份证结果:返回每列和每个结果.

然后是真正令人讨厌的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. 
Run Code Online (Sandbox Code Playgroud)

你是否理解攻击中的SQL是无关紧要的.这证明了mysql_real_escape_string()即使是最不成熟的黑客也很容易被绕过.那是因为它是一种反应性的防御机制.它只修复了数据库中非常有限且已知的漏洞.

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

正确的,唯一的(真正的)防御是主动的:使用准备好的陈述.准备好的语句经过精心设计,因此只执行有效和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())) { }
Run Code Online (Sandbox Code Playgroud)

现在那不是很难吗?它的代码减少了47%(195个字符(PDO)和375个字符(mysql_).这就是我所说的"充满胜利".

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

使用预准备语句可以利用SQL服务器本身的保护措施,因此您可以免受SQL服务器人员所知道的事情的影响.由于这种额外的保护,无论多么彻底,您都比使用转义更安全.

  • @Theodore R. Smith:"所有逃避将永远不足以保护数据库." ---好吧,你能证明**吗?没有很多理论和大声的话.我创建了一个使用mysql_real_escape_string的脚本,并且您正在使用任何类型的SQL注入来获取受保护的数据.好?你是否足够能够做一些真实而不仅仅是哲学的事情? (6认同)
  • 并且你以错误的方式纠正了限制.PDO可以使用限制参数,您可以(并且应该)使用预准备语句.事实上,你的查询汇编代码看起来并没有比常规的mysql更好:) (3认同)
  • 而你准备好的陈述的例子真是太荒谬了:)你偶然碰到它吗? (2认同)
  • "LIKE"表达式的数据应该通过转义`%`和`_`来消毒. (2认同)
  • 太遗憾了.你不明白这一点.它不是"编码器意味着".这是"语言操作者的意思".它的运算符意味着从整个表中返回多个结果,因此,编码器必须对它进行预测.如果只需要一个匹配,则应使用NO LIKE.就这样.和mysql_real_escape_string()不会帮助你使用VARIABLE但是INT类型.你拒绝进一步学习,这让我很难过.这可能是因为你仍然在做大量的"研究",并为自己太骄傲而无法倾听. (2认同)
  • @Monica这是一个误导性的答案.如果你要以这种方式保护你的查询`$ id = mysql_real_escape_string($ _ GET ['id]); $ sql ="SELECT*FROM table WHERE id = $ id"`,你将被黑客入侵.Good Theo称之为挑选,但我称之为SQL注入.这家伙从未使用过他在实践中写的代码.那是个大问题. (2认同)
  • @Theodore R. Smith:当然,准备好的陈述"更安全".但这并不意味着使用`mysql_real_rescape_string`并不安全.你仍然没有给出任何证明'mysql_real_rescape_string`不安全的证据.我再次问你:让我用`mysql_real_rescape_string`编写一个脚本,然后使用任何可能的漏洞来破解它?你同意还是你的话毫无意义? (2认同)

Cha*_*les 8

没有!


重要更新:在测试了Col. Shrapnel提供的可能的漏洞利用代码并查看MySQL版本5.0.22,5.0.45,5.0.77和5.1.48之后,似乎GBK字符集和可能的其他版本与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).


zer*_*kms 7

是.如果你不会忘记:

  1. 使用转义字符串数据 mysql_real_rescape_string()
  2. 投数显式号码(即:$id = (int)$_GET['id'];)

然后你受到了保护.

  • @Theodore R. Smith:嗯,在我的练习中,我从不接受用户输入的字段或表名.是的,查询可以依赖于输入,但我从来没有把数据放到sql中.所以,我认为我的建议仍然是好的和性感的. (2认同)