我们应该始终绑定我们的SQL语句吗?

Tra*_*ven 14 php sql pdo

我一直在研究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();
Run Code Online (Sandbox Code Playgroud)

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

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

dec*_*eze 10

你绝对应该使用prepareAPI并从查询中单独传递值,而不是进行普通的字符串插值(例如"SELECT * FROM foo WHERE bar = '$baz'"bad).

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

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

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

同样,所有选项都同样安全.如果你想一个字符串绑定'foo'使用PDO::PARAM_INT,该字符串将被强制转换为整数,因此必然作为值0.注射不可能.


You*_*nse 10

一个问题有两个.至关重要的是不要混淆它们

  1. 我们是否应始终使用占位符来表示查询中的变量数据?
  2. 我们是否应该始终在应用程序代码中使用某些功能来遵循上述规则?
    此外,根据开幕式下评论澄清,可以看到第三个问题:
  3. 我们应该总是使用第三个参数,还是可以让PDO默认将所有参数绑定为字符串?

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

而对于第二个,为了代码的健全和干燥 -

2.尽可能避免手动绑定.

有许多方法可以避免手动绑定.他们之中有一些是:

  • ORM是简单CRUD操作的绝佳解决方案,必须在现代应用程序中使用.它将完全隐藏SQL,在幕后进行绑定:

    $user = User::model()->findByPk($id);
    
    Run Code Online (Sandbox Code Playgroud)
  • 查询生成器也是一种方法,在一些PHP运算符中伪装SQL,但再次隐藏在幕后的绑定:

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

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

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

从第三个问题开始 - 只要你将数字绑定为字符串(但不是相反!) -

3.使用mysql可以将几乎所有参数作为字符串发送

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