我是否需要清理 laravel 中 DB::query 调用的用户输入


Do I need to clean user input for DB::query calls in laravel?

阅读Laravel文档,我看到:

Note: The Laravel query builder uses PDO parameter binding throughout to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings.

如果我仅按以下方式创建查询,这是否仍然适用?

DB::query("SELECT * from table WHERE id like " . $id);

让我们用这句话来强调关键词:

无需清理作为绑定传递的字符串

在您的示例中,$id不是作为绑定传递的,它只是被注入到原始 SQL 中,因此它不受保护

您应该遵循防止 SQL 注入的标准做法:

  • 在这种情况下,输入始终为整数,您可以使用intval($id)
  • 您可以使用 DB::getPdo()/DB::getReadPdo()获取底层 PDO 对象,并使用 PDO::quote() 正确转义字符串
  • 尽管文档相当差,但 Laravel 的DB外观可以运行完全参数化的查询,例如DB::select('SELECT * FROM users WHERE users.id = ?', array($userId));

参数化查询通常被认为是注入预防的黄金标准,并且是使用查询生成器时 Eloquent 在内部使用的标准。这个想法是,您首先为数据库(或至少是数据库驱动程序)提供完整的查询,而无需用户输入,因此毫无疑问应该使用哪些表和列。然后,您将用户输入作为完全独立的数据传入,这些数据实际上从未写入 SQL,只是应用于您已经发送的查询。

但是,参数化查询无法为您完成所有操作 - 例如,大多数库(包括 PDO)无法将表或列名称绑定为参数。这是因为它实际上会在每次运行时创建一个不同的查询,从而否定查询和数据之间的分离。因此,如果要这样做,则需要其他方法来确保安全性 - 通常,允许值的白名单是最好的主意。

不,DB::query() 不是 Query Builder 概念的一部分。相反,这将受到保护:

DB::table('table')->where('id', 'like', $id)->get();

但是,保护查询的最佳方法是最多使用查询生成器:

DB::table('table')->where('id', 'like', $id)->get();

如果您确实被迫编写原始查询,保护查询的另一种方法是将数据强制转换为它们应该的类型:

DB::query(DB::raw("SELECT * from table WHERE id like " . (int) $id));

在这种情况下,如果$id 'some exploit'则查询将是:

SELECT * from table WHERE id like 0

在查询生成器中,您还可以像这样传递参数(绑定)来强化查询的安全性:

DB::select('SELECT * FROM users WHERE users.id = ?', array($userId));