English 中文(简体)
何时*不*使用预处理语句?
原标题:
  • 时间:2009-02-11 04:47:10
  •  标签:

我正在对一个使用极简数据库的 PHP 驱动网站进行重新设计。原版本使用「伪预处理语句」(PHP 函数,执行引号和参数替换),以防止注入攻击并将数据库逻辑与页面逻辑分离。

似乎自然地用使用PDO和真实的准备语句的对象来替换这些特别的函数,但在了解了它们后,我不太确定了。PDO仍然是一个好主意,但是准备语句的一个主要卖点是能够重复使用它们…而我永远也不会。这是我的设置:

  • The statements are all trivially simple. Most are in the form SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1. The most complex statement in the lot is simply three such selects joined together with UNION ALLs.
  • Each page hit executes at most one statement and executes it only once.
  • I m in a hosted environment and therefore leery of slamming their servers by doing any "stress tests" personally.

鉴于使用准备语句将至少使我进行的数据库往返次数增加一倍,我最好避免它们吗?我可以使用来避免多次数据库访问的开销,同时保留参数化和注入防御的好处吗?或者准备语句API使用的二进制调用与执行非准备查询相比表现得足够好,我不应该担心它吗?

编辑:

感谢大家提供的所有好建议。这是一个我希望能够标记多个答案为“被接受”的例子——有很多不同的观点。但最终,我还是要给Rick他应得的认可...如果没有他的答案,我会在遵循每个人的建议后,显然地做出完全错误的事情。 :-)

模拟预编译语句就是它!

最佳回答

我认为您想要的是PDO :: ATTR_EMULATE_PREPARES。它关闭了本机数据库预处理语句,但仍允许查询绑定以防止SQL注入并保持SQL的整洁性。据我所知,PDO :: MYSQL_ATTR_DIRECT_QUERY完全关闭了查询绑定。

问题回答

今天的软件工程规则:如果它对你没有任何作用,不要使用它。

何时使用准备语句?当您只需要在数据库连接关闭之前运行一次该语句时。

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

我不熟悉PDO,但我敢打赌它提供了一种机制,可以在同一个函数调用中使用给定的值运行参数化查询,如果你不想准备,那么可以作为单独的步骤运行。(例如,类似于run_query("SELECT * FROM users WHERE id = ?", 1)之类的东西。)

此外,如果您在引擎盖下查看,大多数数据库抽象层将准备查询,然后运行它,即使您只告诉它执行静态SQL语句,因此您可能根本无法通过避免明确准备节省到达数据库的旅程。

预处理语句被数千人使用,因此经过了充分的测试(因此可以推断它们是相对安全的)。您的定制解决方案仅由您使用。

你的自定义解决方案存在不安全的风险。使用预处理语句,这样你需要维护的代码会更少。

预处理语句的好处如下:

  • each query is only compiled once
  • mysql will use a more efficient transport format to send data to the server

然而,预处理语句仅在每个连接中持久存在。除非您正在使用连接池,否则如果您仅在每个页面上执行一个语句,则不会有任何好处。简单的查询也不会从更有效的传输格式中受益。

就个人而言,我不会费心。假准备语句可能会提供安全的变量引用,这可能会有用。

老实说,我认为你不应该担心这个问题。然而,我记得一些 PHP 数据访问框架支持预处理语句模式和非预处理语句模式。如果我没记错的话,早些时候 PEAR:DB 支持这样做。

我遇到了与你相同的问题,我有自己的保留意见,所以我没有使用PDO,而是编写了自己的轻量级数据库层,支持准备和标准语句,并在这两种情况下执行正确的转义(防止SQL注入)。我对准备语句的另一个抱怨是,有时将一些不可转义的输入附加到语句中更有效,例如... WHERE id IN(1,2,3...)。

我不太了解PDO,不能告诉你使用它的其他选项。不过,我知道PHP为它支持的所有数据库厂商提供转义函数,你可以在任何数据访问层上自己编写一个小层。





相关问题
热门标签