PHP:mysql_real_escape_string是否足以清理用户输入?

58

在大多数情况下,mysql_real_escape_string 是否足以清理用户输入的内容?

::编辑::

我主要考虑防止SQL注入,但最终想知道是否可以信任应用程序和数据库中传递的用户数据,在使用 mysql_real_escape_string 后是否需要采取额外措施来清理数据。

我知道清理 HTML 字符很重要,但我认为它不是信任用户输入所必需的。

T


3
跨站脚本攻击(XSS)是一个非常严重的问题,如果您忽略它,那么您将会面临同等严重的问题。您必须在输入时进行验证,但是如果在显示用户内容时不去除其中的javascript代码,那么实施会话劫持和XSS攻击将变得非常容易。相对于SQL注入来说,这种攻击方式更加简单易行,但由于比较新颖,所以人们还不太了解。 - Chuck Vose
2
mysql_real_escape_string仅旨在防止SQL注入攻击。对于其他漏洞,您需要其他工具。 - Gumbo
1
@Gumbo mysql_real_we_really_mean_it_this_time_escape_string 将涵盖这些情况。当它在不久的将来被添加时。 - David
1
@David 很滑稽,但是胡说八道,没有一个函数可以完成所有的清理工作。 - Johan
转义字符串并不安全!了解有关MySQLi预处理语句 - Jeff Puckett
10个回答

37

mysql_real_escape_string并不能在所有情况下都足够安全,但它绝对是非常好的朋友。更好的解决方案是使用预处理语句

//example from http://php.net/manual/en/pdo.prepared-statements.php

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);

// insert one row
$name = 'one';
$value = 1;
$stmt->execute();

另外,不要忘记 HTMLPurifier 可以用于丢弃任何无效/可疑字符。

...........

编辑: 根据下面的评论,我需要发布这个链接(我之前应该做过抱歉混淆)

mysql_real_escape_string() versus Prepared Statements

引用:

mysql_real_escape_string()容易出现与addslashes()类似的问题。

Chris Shiflett(安全专家)


5
举一个 Prepared Statements 更加合适的例子,以展示在哪种情况下它比其他方法更为有效。 - Marius
虽然我同意准备语句(prepared statements)更好,但我也非常想知道当mysql_real_escape_string()用于转义查询中的数据时不足够时的情况。 - jasonbar
3
实际上,mysql_real_escape_string并不总是安全的。你应该阅读我的帖子。 - rook
1
@The Rook:这不是mysql_real_escape_and_quote_string()。未能正确引用(或在您的示例中将值转换为整数)并不是mysql_real_escape_string()的问题。 - jasonbar
2
不要忘记使用预处理语句所带来的性能提升! - Dr Hydralisk
显示剩余3条评论

11
你的问题的答案是“不”。mysql_real_escape_string()并不适用于所有用户输入,也不能完全防止SQL注入。addslashes()是另一个在PHP中常用的函数,但它也存在同样的问题。
易受攻击的代码:
mysql_query("select * from user where id=".mysql_real_escape_string($_GET[id]));

POC漏洞利用代码:

http://localhost/sql_test.php?id=1 or sleep(500)

这个补丁是在id周围使用引号:

mysql_query("select * from user where id='".mysql_real_escape_string($_GET[id])."'");

最佳方法是使用参数化查询,这是许多人指出的。Pdo 很好用, adodb 是 php 的另一个流行库。

如果你确实要使用 mysql_real_escape_string ,那么它只应该用于防止 SQL 注入等问题,而不应该用于其他用途。漏洞高度依赖于数据的使用方式。应该根据函数来应用安全措施。是的,XSS 是一个非常严重的问题。不过滤 HTML 是一个严重的错误,黑客会利用它来攻击你。请阅读 xss faq


2
那与mysql_real_escape_string()防止注入的能力有什么关系?正确引用或将您的值强制转换为整数。 - jasonbar
2
没错,但这并不意味着 mysql_real_escape_string() 不适用于为 SQL 转义 字符串。编辑:是的,预处理语句更好。 - jasonbar
3
没错,就像我之前提到的那样,它不是 mysql_real_escape_and_quote_string()。再次强调,这并不是函数本身的问题,而是由于错误的使用导致的问题。我仍然希望看到一个 mysql_real_escape_string() 无法解决的例子。 - jasonbar
2
不,显然我不这么认为。你的论点就像是说 while() 不适用于迭代,因为你可以使用 while(1);。 - jasonbar
1
谢谢您指出这一点。在这种情况下,我喜欢将floatval()包装在任何作为数字输入的内容周围。 - Jage
显示剩余3条评论

5

对于数据库,是的。你需要考虑适当地转义/编码输出数据。

你还应该考虑根据预期内容验证输入。

你有没有考虑使用预处理语句?PHP提供了许多与数据库交互的方式,其中大多数比mysql_*函数更好。

PDOMDB2MySQL改进版可以帮助你入门。


对于数据库来说,"To the database" 意味着输出的结果。不是输入。 - symcbean

4

什么情况?

对于SQL查询,这很好。 (准备好的语句更好 - 我投 PDO - 但函数可以很好地转义。) 对于HTML等内容,它不是工作的工具 - 尝试一个通用的 htmlspecialchars 或一个更精确的工具,如 HTML Purifier

针对编辑进行回应: 您可以添加的唯一其他层是数据验证,例如确认如果您将整数放入数据库,并且您期望获得正整数,则在尝试输入负整数时向用户返回错误。就数据完整性而言,mysql_real_escape_string 是最好的转义工具(尽管准备好的语句是一种更干净的系统,可以完全避免转义)。


再说一遍,答案几乎正确 - 但问题是关于输入 - 而不是输出。 - symcbean
有时输入直接输出,例如 <?php echo $_GET['name']; ?> - Matchu

2

mysql_real_escape_string() 函数仅仅能够预防 SQL 注入攻击,但它无法帮助你预防跨站脚本攻击。针对这种情况,建议在输出用户输入的数据之前,使用 htmlspecialchars() 函数进行处理。


1
SQL注入很容易理解,但XSS目前是一个巨大的问题。感谢您提出这个问题。 - Chuck Vose

1

你可以尝试两种方式,就像这样

function clean_input($instr) {

     // Note that PHP performs addslashes() on GET/POST data.
     // Avoid double escaping by checking the setting before doing this.
    if(get_magic_quotes_gpc()) {
        $str = stripslashes($instr);
    }
    return mysql_real_escape_string(strip_tags(trim($instr)));
}

我使用了这种技术。感谢@crafter。 - Kabir Hossain

1

有两种方法,一种是使用预处理语句(如其他答案中提到的),但这会使您的应用程序变慢,因为现在您需要向数据库发送两个请求,而不是一个。如果您可以接受性能下降,那就去用吧;预处理语句使您的代码更漂亮,更容易处理。

如果您选择使用mysql_real_escape_string,请确保转义所有不可信任的字符串。(mysql_real_escape_string)转义后的字符串是SQL注入安全的。如果您没有转义所有的字符串,则不安全。您应该真正将mysql_real_escape_string与输入验证结合使用;检查您期望保存数字的变量是否真的是数字,并且在预期范围内。记住,永远不要相信用户。


1

有不同类型的“清理”。

mysql_real_escape_string 对于数据库数据已足够,但如果是HTML,则仍将由浏览器在显示时进行评估。

要从用户输入中删除HTML,可以使用strip_tags

我建议您考虑使用PDO而不是常规的MySQL内容,因为它支持预处理语句,这些语句可以直接处理无效数据的转义。


0

我想提醒一下,PHP 5.2+ 版本已经拥有输入过滤函数,可以以各种方式对用户输入进行消毒处理。

这里是手册入口,以及Matt Butcher的博客文章,详细介绍了它们的优点。


请注意,这并不能防止 SQL 注入攻击,但可以防止 XSS 攻击! - Alfred

0

2
两年前,在这个帖子中有很多其他的答案 - 这真的很重要吗? - Marek Karbarz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接