【问题标题】:How does sprintf() protect against SQL injection?sprintf() 如何防止 SQL 注入?
【发布时间】:2011-10-02 13:38:56
【问题描述】:

我听说sprintf() 可以防止 SQL 注入。这是真的吗?如果有,怎么做?

为什么人们推荐这样写查询:

$sql = sprintf('SELECT * FROM TABLE WHERE COL1 = %s AND COL2 = %s',$col1,$col2);

【问题讨论】:

  • 有哪些人推荐这样的东西?
  • 你的意思可能是准备好的陈述,这是一个不同的主题。

标签: php mysql sql-injection


【解决方案1】:

sprintf 不会保护你!它只替换了%s

你必须 mysql_real_escape_string 这样:

$sql = sprintf('SELECT * FROM TABLE WHERE COL1 = "%s" AND COL2 = "%s"',
mysql_real_escape_string($col1),
mysql_real_escape_string($col2));

注射更安全

注意:我建议你看看PDO,这是我喜欢用于 DBconections 和查询的东西

【讨论】:

  • @beardthatcode mysqli_real_escape_string 应该被使用。 mysql_ * 函数自 PHP 5.5 起已被弃用,自 PHP 7 起已被删除。顺便说一句。 mysqli 还支持准备好的语句。就个人而言,我建议所有传入的变量(如 $_GET、$_POST、$_REQUEST)都通过 Web 应用程序防火墙 (WAF) 运行。我也在这里读到应该检查 $_FILES,但我不明白为什么这个超全局可能包含恶意内容。
  • 另外,我总是将表名和行名括在反引号中。因此,该语句变得更具可读性。此外,使用反引号您不必担心保留名称。因此,您可以例如命名排序行 ORDER 而不会出错。没有你会得到一个。
【解决方案2】:

这没有任何保护作用。使用sprintf 可以使代码更具可读性,然后放入和取出字符串以在每个变量上运行mysql_real_escape_string……但该示例最后并没有转义变量,因此失去了优势。

如果您想要体面的保护,请使用提供bound parameters 的东西。

【讨论】:

  • 哎呀。 stupid_overlong_not_fake_function_names 在早上的这个时候很容易引入错别字。 :)
【解决方案3】:

使用 sprintf 可以防止数字字段的 SQL 注入:

$sql = sprintf("SELECT * FROM table WHERE col1 = %i", $col1);

通过以这种方式使用 sprintf,您可以确保 $col1 将被转换为整数 - 尽管它可能会生成错误或警告,如果它不是真正的整数。

防止 SQL 注入的正确方法是检查所有输入值并进行转义。但这在其他问题中有更全面的介绍,所以我不打算在这里详细介绍。

【讨论】:

  • 但是对于整数,无论​​如何您都不必采取特殊的预防措施。
  • 当然可以...如果用户输入的“整数”看起来像这样:“; DROP TABLE users;”怎么办?
  • 那么就不是整数了,很简单。我没有说你可以放弃类型检查。
  • 你说“没有特别的预防措施”——我会考虑类型检查作为预防措施。在任何情况下,使用 sprintf 来防止任何数据的 SQL 注入都是一种愚蠢的方法。
  • 或者简单地说 $col1=$col1+0;在使用它之前。
【解决方案4】:

它显然没有,如果你真的在书或教程中读过它,你应该自动丢弃它以供将来参考。

但是,它可能是一种实用的方法来生成需要进一步处理的输出。请比较:

echo '<p>Hello, <strong></strong>' . htmlspecialchars($name) . ', welcome to ' . htmlspecialchars($place). '</p>';

echo sprintf('<p>Hello, <strong>%s</strong>, welcome to %s</p>',
    htmlspecialchars($name),
    htmlspecialchars($place)
);

这同样适用于其他类型的输出,例如 SQL 代码,但当然您仍然需要做一些输入以使其安全:sprintf() 只是一个不知道 SQL 和数据库的常规字符串函数。

请注意,绑定参数使用类似的语法:

// Fictional DB abstraction layer
$sql = 'SELECT foo_id
    FROM foo
    WHERE name=:name AND status=:status';
$params = array(
    'name' => $name,
    'status' => $status,
);
$result = $db->run($sql, $params);

这就是为什么我特别发现使用那些提供这种语法的数据库库(例如 PDO)更容易。

【讨论】:

    猜你喜欢
    • 2015-09-07
    • 2011-06-21
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 2013-05-20
    • 2020-09-08
    • 2011-11-03
    相关资源
    最近更新 更多