什么时候*不*使用准备好的语句?

问题描述 投票:0回答:6

我正在重新设计一个使用最小数据库的 PHP 驱动的网站。原始版本使用“伪准备语句”(进行引用和参数替换的 PHP 函数)来防止注入攻击并将数据库逻辑与页面逻辑分开。

用使用 PDO 和真正准备好的语句的对象替换这些临时函数似乎很自然,但在阅读它们之后,我不太确定。 PDO 看起来仍然是一个好主意,但准备好的语句的主要卖点之一是能够重用它们……我永远不会。这是我的设置:

  • 这些陈述都非常简单。大多数都是
    SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1
    的形式。其中最复杂的语句就是三个这样的选择用
    UNION ALL
    连接在一起。
  • 每个页面点击最多执行一条语句,并且只执行一次。
  • 我处于托管环境中,因此对亲自进行任何“压力测试”来攻击他们的服务器持谨慎态度。
考虑到使用准备好的语句至少会使我进行的数据库往返次数增加一倍,我是否最好避免使用它们?我可以使用

PDO::MYSQL_ATTR_DIRECT_QUERY

 来避免多次数据库访问的开销,同时保留参数化和注入防御的好处吗?或者,与执行非准备好的查询相比,准备好的语句 API 使用的二进制调用是否表现得足够好,我不应该担心?

php mysql pdo prepared-statement
6个回答
24
投票

当今的软件工程规则:如果它不能为你做任何事,就不要使用它。


18
投票
我认为你想要 PDO::ATTR_EMULATE_PREPARES。这将关闭本机数据库准备好的语句,但仍然允许查询绑定以防止 sql 注入并保持 sql 整洁。据我了解,PDO::MYSQL_ATTR_DIRECT_QUERY 完全关闭查询绑定。


15
投票
何时

使用准备好的语句? 当您只想在数据库连接消失之前运行该语句一次时。

何时

使用绑定查询参数(这实际上是大多数人使用准备好的语句来获取的)? 我倾向于说“从不”,而且我真的很想说“从不”,但现实是大多数数据库和一些数据库抽象层在某些情况下不允许您绑定参数,因此您在这些情况下被迫不使用它们。 但在任何其他时候,它都会让您的生活变得更简单,并且您的代码使用它们会更安全。

我不熟悉 PDO,但我敢打赌它提供了一种机制,如果您不想准备,则可以使用同一函数调用中给出的值运行参数化查询,然后作为单独的步骤运行。 (例如,类似

run_query("SELECT * FROM users WHERE id = ?", 1)

 或类似内容。)

此外,如果您深入了解,大多数数据库抽象层都会准备查询,然后运行它,即使您只是告诉它执行静态 SQL 语句。 因此,无论如何,您可能都不会通过避免显式准备来节省数据库之旅。


11
投票
准备好的声明正在被成千上万的人使用,因此经过了充分的测试(因此可以推断它们是相当安全的)。您的自定义解决方案仅供您使用。

您的自定义解决方案不安全的可能性非常高。使用准备好的语句。这样你就必须维护更少的代码。


7
投票
准备好的报表的好处如下:

    每个查询仅编译一次
  • mysql将使用更高效的传输格式向服务器发送数据
但是,准备好的语句仅在每个连接中持续存在。除非您使用连接池,否则如果您每页仅执行一条语句,则不会有任何好处。简单的查询也不会从更高效的传输格式中受益。

就我个人而言,我不会打扰。伪准备语句可能对于它们可能提供的安全变量引用很有用。


2
投票
老实说,我认为你不应该担心。不过,我记得许多 PHP 数据访问框架都支持准备语句模式和非准备语句模式。如果我没记错的话,PEAR:DB 当年就这么做过。

我遇到了和你一样的问题,我也有自己的保留,所以我最终没有使用 PDO,而是编写了自己的轻量级数据库层,该数据库层支持准备和标准语句,并在中执行正确的转义(sql 注入预防)两种情况。我对准备的另一个抱怨是,有时将一些不可转义的输入附加到诸如 ... WHERE id IN (1, 2, 3...) 之类的语句中会更有效。

我对 PDO 的了解还不够,无法告诉您使用它还有哪些其他选项。然而,我确实知道 PHP 具有可用于它支持的所有数据库供应商的转义函数,并且您可以在您所坚持的任何数据访问层之上滚动您自己的小层。

© www.soinside.com 2019 - 2024. All rights reserved.