在没有预准备语句的情况下防止SQL注入(JDBC)

时间:2009-08-06 13:08:58

标签: java sql jdbc sql-injection prepared-statement

我有一个数据库日志追加器,每隔一段时间就会在数据库中插入可变数量的日志行。

我想以防止SQL注入但不使用服务器端预处理语句的方式创建SQL语句(因为我在每个选择中都有可变数量的行,缓存它们会有所帮助但可能会受到伤害这里的表现。)

我也喜欢准备好的语句的便利性,并且更喜欢它们串联连接。是否有类似“客户端准备好的声明”的内容?

6 个答案:

答案 0 :(得分:7)

听起来你没有对最简单的解决方案 - 预备语句进行基准测试。你说他们“可能会损害表现”,但在你测试之前,你真的不会知道。

我会肯定首先测试预备语句。即使他们会略微妨碍性能,在您测试它们之前,您将无法知道您是否仍能达到所需的性能。

为什么在没有尝试过最明显的解决方案时花时间寻找替代解决方案?

如果您发现准备好的语句执行计划缓存 代价高昂,您可能会发现有特定于数据库的方法可以调整或禁用它。

答案 1 :(得分:2)

不确定我是否正确理解了您的问题。 PreparedStatement中的某些内容是否符合您的需求?

我认为语句是否在服务器端缓存是数据库驱动程序和您正在使用的特定数据库的实现细节;如果你的查询/语句随时间变化而不会产生影响 - 那么就不会使用缓存/编译语句。

答案 2 :(得分:2)

首先,Jon的答案是你应该采用最明显的解决方案,直到绩效被证明是一个问题,这当然是正确的方法。

我不认为您的表现问题是错误的。我确实看到预编译的复杂语句在性能规模上显着失败(在MS-SQL 2000上)。原因是语句太复杂了,它根据参数有几个潜在的执行路径,但是编译为一组参数锁定了一个,而下一组参数太慢,而重新编译会强制重新计算执行计划更适合于不同的参数集。

但是,直到你在实践中看到这个问题时,这个问题还很遥远。

这里的根本问题是参数转义是特定于数据库的,所以除非你的数据库的JDBC驱动程序给你一些非标准的东西(极不可能),你将不得不拥有一个不同的库或不同的转义机制,非常特定于这个数据库。

从您的问题的措辞来看,这听起来并不像您的表现问题尚未找到(或开发)这样的解决方案。

还应该注意的是,尽管JDBC驱动程序可能并非都是这样,但从技术上讲,根据规范,预编译应该在PreparedStatement对象中缓存,如果你抛弃它并每次都获得一个新的PreparedStatement,它实际上不应该缓存任何东西,因此整个问题可能是静音的,需要针对您的特定JDBC驱动程序进行调查。

来自规范:

  

可以预编译带有或不带IN参数的SQL语句并将其存储在PreparedStatement对象中。然后,可以使用此对象多次有效地执行此语句。

答案 3 :(得分:0)

使用常规准备声明有什么问题,例如在以下伪代码中:

DatabaseConnection connection;
PreparedStatement insertStatement = ...;

    ...

connection.beginTransaction();
for (Item item : items)
{
   insertStatement.setParameter(1, item);
   insertStatement.execute();
}
connection.commitTransaction();

智能数据库实现会将多个插入批处理到与数据库服务器的一个通信交换中。

答案 4 :(得分:0)

我想不出你不应该使用准备好的陈述的原因。如果您使用连接池在J2EE服务器上运行此服务器,则服务器会保持连接打开,并且服务器会缓存您的访问/执行计划。这不是它缓存的数据!

如果您每次都关闭连接,那么您可能无法获得任何性能。但是你仍然可以获得SQL注入预防

大多数java性能调优书都会告诉你: Java performance tuning

答案 5 :(得分:-1)

准备好的声明不关心客户端或服务器端。

使用它们并删除任何SQL字符串连接。没有一个理由不使用准备好的陈述。