我们应该总是绑定SQL语句吗?


Should we always bind our SQL statements?

我一直在研究PDO的bindValue()。我知道用PDO准备SQL语句可以防止SQL注入的发生。

代码例子:

$stmt = $dbh->prepare('SELECT * FROM articles WHERE id = :id AND title = :title');
$stmt->bindValue(':id', PDO::PARAM_INT);
$stmt->bindValue(':title', PDO::PARAM_STR);
$stmt->execute();

通过将ID绑定为数字,并且将Title绑定为字符串,我们可以限制当有人试图在代码中进行SQL注入时所造成的损害。

我们是否应该总是将我们的值与PDO::PARAM_绑定,以便我们可以限制在SQL注入中可以从数据库提取的内容?在做bindValue()时,这是否增加了PDO的安全性?

一个问题包含两个问题。重要的是不要混淆它们

    我们应该总是使用占位符来表示查询中的变量数据吗?我们是否应该总是在应用程序代码中使用某些函数来遵循上述规则?
    另外,从开篇评论的澄清中,可以看出第三个问题:
  1. 我们应该总是使用第三个参数,还是让PDO将所有参数绑定为默认字符串?

1。对于第一个问题,答案是绝对肯定的——是。

而对于第二个,为了代码的完整性和干涩-

2。尽量避免手工绑定。

有很多方法可以避免手工绑定。其中一些是:
  • ORM对于简单的CRUD操作是一个很好的解决方案,必须在现代应用程序中拥有。它将完全隐藏SQL,在幕后进行绑定:

    $user = User::model()->findByPk($id);
    
  • Query Builder也是一种方式,在一些PHP操作符中隐藏SQL,但在幕后隐藏绑定:

    $user = $db->select('*')->from('users')->where('id = ?', $id)->fetch();
    
  • 一些抽象库可能会通过类型暗示占位符来处理传递的数据,从而再次隐藏实际绑定:

    $user = $db->getRow("SELECT * FROM users WHERE id =?i", $id);
    
  • 如果你还在用上个世纪的方式使用PHP,并且在所有的代码中都有原始的PDO,那么你可以在execute()中传递变量,仍然节省了大量的输入:

    $stmt = $dbh->prepare('SELECT * FROM users WHERE id = ?');
    $stmt->execute([$id]);
    $user = $stmt->fetch();
    

关于第三个问题——只要你将数字绑定为字符串(而不是相反!)——

3。对于mysql来说,将几乎所有参数作为字符串

发送是没问题的。

作为mysql将始终转换您的数据到适当的类型。我所知道的唯一情况是,在LIMIT子句中,您不能将数字格式化为字符串-因此,唯一相关的情况是当PDO设置为仿真模式时,您必须在LIMIT子句中传递参数。在所有其他情况下,您可以省略第三个参数,以及显式调用bindValue(),没有任何问题。

你绝对应该使用prepare API并从查询中单独传递值,而不是做纯字符串插值(例如"SELECT * FROM foo WHERE bar = '$baz'"bad)。

对于绑定参数,您有三个选项:

  • bindParam
  • bindValue
  • execute

你使用哪一种并不重要,它们都同样安全。有关差异的一些详细信息,请参阅以下回答:

  • bindValue()和bindParam()之间的混淆?
  • 使用PDO而不绑定

当使用bindParambindValue时,传递第三个PDO::PARAM_参数类型是可选的。如果不传递它,它默认将参数绑定为字符串。这意味着您最终得到的查询可能相当于... WHERE foo = '42'而不是... WHERE foo = 42。这取决于你的数据库如何处理这个问题。MySQL会根据需要自动将字符串转换为数字,就像PHP一样(例如在'42' + 1中)。其他数据库可能对类型更挑剔。

同样,所有选项都同样安全。如果您试图使用PDO::PARAM_INT绑定字符串'foo',则该字符串将被强制转换为整数,并相应地绑定为值0

是的,您应该始终将参数与预处理语句绑定。它更安全,并且限制了SQL注入。但这并不是查询参数必须做的唯一事情:需要正确的类型控制,最好是将一行映射到对象中,并在其中包含无效数据时抛出异常。

希望我能帮上忙!

是的,绑定是可行的方法。或参数化查询,更广义的术语。

@Theo很好地解释了为什么参数化查询是一种方式

您也可以使用存储过程来获得额外的安全性,但是如果您有一个应用程序到一个数据库,那么这是多余的。在处理数据

时,多个应用程序可以在一个数据库中使用,以确保一致性。