当*不*使用准备好的语句?
我正在重新devise一个使用最小数据库的PHP驱动的网站。 原始版本使用“伪准备语句”(引用和参数replace的PHP函数)来防止注入攻击并将数据库逻辑从页面逻辑中分离出来。
用一个使用PDO和真实准备好的语句的对象代替这些特定的函数似乎是很自然的,但是在我读完这些对象之后,我不太确定。 PDO似乎仍然是一个好主意,但准备好的陈述的主要卖点之一就是能够重用它们,这是我永远不会想到的。 这是我的设置:
- 这些陈述都非常简单。 大多数是在forms
SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1
SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1
。 在这个地段最复杂的陈述只是三个这样的select联合在一起的UNION ALL
。 - 每个页面命中至多执行一个语句,并只执行一次。
- 我处于一个托pipe环境,因此对个人进行任何“压力testing”的抨击他们的服务器持怀疑态度。
鉴于使用准备好的语句,至less会使我所做的数据库往返次数增加一倍,我最好是避免它们? 我可以使用PDO::MYSQL_ATTR_DIRECT_QUERY
避免多个数据库行程的开销,同时保留参数化和注入防御的好处吗? 或者,执行准备好的语句API使用的二进制调用与执行未准备好的查询相比,执行得还不错,我不应该担心这个问题呢?
编辑:
感谢所有的好build议,伙计们。 这是我希望我可以将多个答案标记为“已接受”的地方 – 有很多不同的观点。 但最终,我必须给予他应有的回报……如果没有他的回答,即使在听取了大家的意见后,我也会幸福地离开,完成了错误的事情。 🙂
仿真准备好的声明是!
我想你想PDO :: ATTR_EMULATE_PREPARES。 这closures本地数据库准备语句,但仍然允许查询绑定,以防止SQL注入,并保持你的SQL整洁。 据我所知,PDO :: MYSQL_ATTR_DIRECT_QUERY完全closures查询绑定。
今天的软件工程规则:如果它不会为你做任何事情,不要使用它。
何时不使用准备好的语句? 在db连接消失之前,你只要运行一次语句。
何时不使用绑定查询参数(这是大多数人使用准备语句得到的)? 我倾向于说“从来没有”,我真的想说“从来没有”,但事实是,大多数数据库和一些数据库抽象层有一定的情况下,他们不会让你绑定参数,所以你在这种情况下不得不使用它们。 但是,任何其他时间,它都会使您的生活变得更简单,使用它们的代码更安全。
我不熟悉PDO,但我敢打赌,它提供了一个机制,用于在不需要准备的情况下使用同一函数调用中给定的值运行参数化查询,然后作为单独的步骤运行。 (例如,像run_query("SELECT * FROM users WHERE id = ?", 1)
或类似的东西。
另外,如果你仔细看看底层,大多数数据库抽象层将准备查询,然后运行它,即使你只是告诉它执行一个静态的SQL语句。 所以你可能不会保存一下数据库,避免明确的准备。
准备好的陈述正在被成千上万的人使用,因此经过了充分的testing(因此可以推断出它们是相当安全的)。 您的自定义解决scheme仅供您使用。
您的自定义解决scheme不安全的机会相当高。 使用准备的语句。 你必须这样维护更less的代码。
准备好的陈述的好处如下:
- 每个查询只编译一次
- mysql将使用更高效的传输格式将数据发送到服务器
但是,准备好的语句只能在每个连接上持续。 除非你使用连接池,否则如果你只在每个页面上做一个语句就没有任何好处。 简单的查询也不会从更高效的传输格式中受益。
我个人不会打扰。 准备好的语句对于他们推测可以提供的安全variables引用很有用。
老实说,我不认为你应该担心。 但是,我记得一些PHP数据访问框架支持准备语句模式和非准备语句模式。 如果我没有记错的话,PEAR:DB当天就回来了。
我遇到了同样的问题,因为我自己有所保留,所以不是使用PDO,而是编写了我自己的支持准备和标准语句的轻量级数据库层,并在两个版本中都执行了正确的转义案例。 我准备的另一个抱怨是,有时候把一些不可能的input附加到像WHERE ID IN(1,2,3 …)这样的语句上会更有效率。
我不太了解PDO,告诉你还有什么其他的select。 不过,我知道PHP为它所支持的所有数据库供应商提供了可用的转义函数,并且您可以在自己的任何数据访问层之上推出自己的一层。