【问题标题】:Concrete example of where mysql_real_escape_string fails and Prepared Statements are necessarymysql_real_escape_string 失败且需要准备好的语句的具体示例
【发布时间】:2012-02-22 15:34:51
【问题描述】:

我一直在使用 mysql_real_escape_string 和其他函数来清理我的输入,并且最近读到 Prepared Statements 是真正安全的唯一方法。但是我不愿意使用它们有两个原因:我不想重写代码,而且我读到使用它们会影响性能(查询在此应用程序中广泛使用)。

所以我正在寻找一个最近的具体示例,说明 mysql_real_escape_string 在查询中失败的位置,解决方法是使用准备好的语句(即没有办法进一步清理输入并保证它是安全的)。

我问这个是因为我能找到的唯一一个符合上述标准的例子是很久以前的,并且已经在更新版本的 php.ini 中进行了修补。

【问题讨论】:

  • 你能从你读到“准备好的声明是真正安全的唯一方法”的地方获取信息吗?似乎很奇怪,做出这样的声明却没有提供一些关于为什么 mysql_real_escape_string 被认为不那么安全的见解。
  • 请看这个stackoverflow问题的最高答案:stackoverflow.com/questions/2353666/…

标签: php prepared-statement mysql-real-escape-string


【解决方案1】:

mysql_real_escape_string() 的全部目的是 100% 保证您使用它转义的数据中不会有 SQL 注入。它远远优于addslashes(),因为它考虑了当前连接的字符编码。

如果这个函数的实际实现中没有严重的bug,那么可以安全使用

人们不希望您使用它的原因是您可能在某个地方忘记,从而打开一个安全漏洞。准备好的语句更难搞砸,但如果你正确地转义数据,构建你自己的 SQL 从根本上没有错。

编辑:

请注意在建立连接后可能会更改连接的字符集,因此与mysql_real_escape_string 不同步。我还没有确认情况仍然如此。

另请注意,mysql_real_escape_string() 必须是在将数据与 SQL 连接之前对数据执行的最后一次操作。

另外,不要忘记引号!例如。 AND name = "' . mysql_real_escape_string($name) . '"

【讨论】:

  • 此外,无论如何,您都需要将数据传递给准备好的语句,因此,如果您无法逃避传递给数据库的内容,那您就完蛋了
  • 请看这个stackoverflow问题的最高答案:stackoverflow.com/questions/2353666/…
  • 但是正确传递给准备好的语句的数据不需要转义(就 SQL 注入而言)。准备好的语句知道什么是数据,什么是查询语法的一部分。不过,您可以以不正确的方式将数据传递给准备好的语句。即,将数据连接到查询字符串。如果您必须这样做,请在其上使用 mysql_real_escape_string()。
  • 或 intval() 用于整数和 floatval() 用于浮点数。
【解决方案2】:

mysql_real_escape_string 是 100% 可靠的。这就是你对失败后的转义数据所做的事情。

例如

$safe = mysql_real_escape_string('some nasty injection-riddled data here');
$unsafe = htmlspecialchars($safe);

m_r_e_s 将完美地完成它的工作,然后你可能会通过之后再次摆弄字符串来撤销一切。

m_r_e_s 应该是在用于 SQL 查询之前对字符串执行的最后一个操作。

【讨论】:

  • 谢谢。但是您对此有何看法:stackoverflow.com/questions/2353666/…
  • XSS 与 sql 注入完全无关。它们是完全不同的威胁,m_r_e_s 既不会阻止也不会鼓励 xss 的可能性。那不是它的工作。
【解决方案3】:

来自函数的 PHP 文档 (http://php.net/mysql_real_escape_string),它说“mysql_real_escape_string() 调用 MySQL 的库函数 mysql_real_escape_string,它在以下字符前面加上反斜杠:\x00、\n、\r、\、'、”和\x1a。” 因此,它的有用性取决于上下文。因此,例如,如果您有以下情况:

$user_input = mysql_real_escape_string($_GET['user_input']);
$query = "SELECT * FROM `users` WHERE `id` = $user_input";
$result = mysql_query($query);

好吧,那将是相当愚蠢的。因为如果字符串是0 or 9=9,那么它不包含函数转义的任何字符。但是,当注入 $query 文字时,它会产生:

$query = "SELECT * FROM `users` WHERE `id` = 0 or 9=9";

这将返回users 表中的所有行......这可能不是程序员的意图。

因此,总而言之,如果用户输入由 mysql_real_escape_string() 处理,但在整数或其他数字数据类型的上下文中使用,那么它将无法提供足够的保护。

使用准备好的语句,您可以确保每个值不仅被转义,而且被验证为正确的数据类型。

在上面的示例中,最安全的处理方法是使用 intval() 函数而不是 mysql_real_escape_string() 函数。

希望这是有道理的。

【讨论】:

    猜你喜欢
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 2014-01-29
    相关资源
    最近更新 更多