7

根据 php.net 我应该使用 mysql_real_escape_string()并关闭魔术引号,因为它已被弃用。

所以我把它关掉了,我使用了mysql_real_escape_string(),但是像下面的代码那样使用它就足够了吗?

$value = "It's Time!";
$escaped_value = mysql_real_escape_string($value);

mysql_query("INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")");

当我检查数据库中的数据时,它看起来与 $value so"It's Time"和 not相同"It\'s Time"。这是正常的吗?这不应该在引号前添加一个斜杠吗?

4

3 回答 3

10

简短的回答

这是对的。

长答案

这是正确的,但是您的问题表明对这里发生的事情缺乏深入的了解。这是您的查询:

INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")

让我们看看如果你不逃跑会发生什么,并且用户输入以下数据:

Eve'

请记住,您只是将字符串传递给 MySQL,插入是由 PHP 的字符串处理完成的。这意味着在这种情况下,发送到 mysql_query 的查询是:

INSERT INTO table (column, column2) VALUES ('Eve'', "0")

这是一个语法错误,会导致页面错误。现在,当像我这样的用户(即一个想要让你的一天变得痛苦的混蛋:D)发现其中一个时,我们知道是时候玩了。如果用户提供以下数据会怎样?

Eve', "0"); DROP TABLE table--

我们的查询扩展为:

INSERT INTO table (column, column2) VALUES ('Eve', "0"); DROP TABLE table--', "0")

这不是语法错误,但它是有问题的......我们现在正在执行一个我们从未打算过的查询!(如果您不认识它,“--”表示 SQL 中的注释,即“忽略此点之后的所有内容”)。

现在这不可能在这个确切的实例中发生(mysql_query 不支持多个查询),但这是您试图阻止的那种攻击 - 一类称为SQL 注入的攻击。让我们看看使用 mysql_real_escape_string 时会发生什么!

输入的数据变为:

Eve\', \"0\"); DROP TABLE table--

这意味着我们的查询字符串如下所示:

INSERT INTO table (column, column2) VALUES ('Eve\', \"0\"); DROP TABLE table--}', "0")

这很好!用户输入的数据将在他们输入时存储在数据库中。不是没有引号,也不是有额外的反斜杠,而是在他们输入时。这很重要。如果您以任何其他方式存储数据,您稍后会遇到问题,包括反转义或双重转义。此外,添加额外的斜线或类似的东西通常最终会以一种或另一种方式暴露给用户,这是一个巨大的警告信号,表明事情可能没有被正确地转义。你想避免做错事,你特别想避免做错事和做广告,这将我带到下一节:

转义数据的替代方法

  1. 魔术报价。正如您所指出的,已弃用(并且有充分的理由),避免。

  2. 不要逃避您的数据。我建议不要使用此选项。

  3. 从输入中去除坏字符。在几乎所有情况下都很烦人,您应该存储用户输入的内容,而不是技术上易于存储的内容。

  4. 禁止输入错误字符。有时可以接受(信用卡号字段不需要处理引号),有时很烦人,有时是一个巨大的警告标志(例如在密码字段上时)

  5. 准备好的陈述。我说字符串中变量的“填充”是由 PHP 完成的,而 MySQL 只是获取一个查询字符串,因此需要转义。准备好的语句通过更加智能来减轻这项工作,并且使用准备好的语句看起来像这样(警告:伪代码):

    $statement = $db->prepare('INSERT INTO table (column, column2) VALUES ("%1", "%2")'); $result = $statement->execute($value1, $value2);

有一个关于 SQL 转义方法的很好的 Stack Overflow 问题,那里的答案更深入,所以你可能想读一下。

就个人而言,这是我喜欢的选项。您不能忘记以这种方式转义变量并将其插入到数据库中 - 要么值被正确编组,要么它们没有到达数据库附近,没有中途选项。也就是说,假设您强制所有查询都通过准备好的语句,并且没有像这样的字符串连接

$db->prepare('INSERT INTO table VALUES('.$value.')'))

已经完成了。在我看来,这比跟踪哪些变量被清理,哪些变量没有被清理更容易。有些人喜欢在字符串一来自用户时就对其进行转义,但如果他们可以去数据库以外的任何地方——回到 HTML、内存缓存等,那就太尴尬了。如果你打算自己做,我可能会建议一些匈牙利符号,例如:

$uValue = $_POST['value'];
$sValue = escape($uValue);
$db->query('INSERT INTO table VALUES(' . $sValue .')');

我第一次看到这个想法是在Joel Spolsky的一篇优秀的文章Making Wrong Code Look Wrong中。

结论

希望您现在可以更好地准备制作防注射网站。无论您选择哪种方法,祝您好运,并确保您始终在所有用户输入到达数据库之前对其进行转义!;)

于 2011-02-01T14:01:08.197 回答
10

这是正确的行为,并且有效!引号在查询中转义,而不是在数据库中。SQL查询中的\'必须转换为数据库里面的'。

您对字符串进行转义,因此 SQL 查询不会弄乱,并允许在数据库中输入引号,而 SQL 查询不会将它们解释为控制字符。

您的转义查询将是:

mysql_query("INSERT INTO table (column, column2) VALUES ('It\'s time', "0")");

您的数据库数据应该是“是时候了”。

如果没有逃脱,它将是:

mysql_query("INSERT INTO table (column, column2) VALUES ('It's time', "0")");

它会吐出一个关于“s time”的错误(因为它只会解释到下一个引号字符,并且只会看到“It”。)和“It's time!” 只是一个无害的字符串,但如果你不逃避你的角色,很多攻击可能会由此产生。

于 2011-02-01T13:39:31.523 回答
0

mysql_real_escape_string() 通常足以防止SQL 注入

您还应该过滤从用户那里获得的数值(通过使用 intval())。

于 2011-02-01T13:40:18.433 回答