当PreparedStatement无法工作时,如何在JDBC中转义SQL参数?

时间:2016-01-23 02:58:07

标签: postgresql jdbc escaping postgresql-9.4

我有一个我想传递给SQL的字符串。要防止SQL注入以及其他引用和转义问题,最佳做法是使用PreparedStatement?。例如:

val ps = conn.prepareStatement("select * from foo where name = ?")
ps.setString(1, name)

但对于某些SQL代码,这不会起作用。例如,这里是PostgreSQL,试图创建一个视图。

 val ps = conn.prepareStatement("create temp view v1 as select * from foo where name = ?")
 ps.setString(1, name)
 val rs = ps.execute()

这会引发错误:

org.postgresql.util.PSQLException: ERROR: there is no parameter $1

显然不允许参数create view。你如何解决这个问题并安全地逃离这个字符串?

1 个答案:

答案 0 :(得分:0)

Prepared语句用于计划复杂语句一次,然后使用不同的参数值执行多次(=非常多次)。简单的陈述使用准备好的陈述没有明显的好处,因为规划它们是微不足道的。完全不支持DDL语句,因此很可能是错误的原因,尽管错误消息令人困惑。

来自documentation

PREPARE name [(data_type [,...])] AS 语句

声明
任何SELECT,INSERT,UPDATE,DELETE或VALUES语句。

PreparedStatement类确实记录了您可以在executeUpdate()方法中使用DDL,但从逻辑角度来看,这只是无意义,至少在PostgreSQL中。

相反,您应该使用Statement,然后调用execute()executeUpdate()(有点奇怪,后一种方法将支持DDL语句,因为没有执行更新)。 / p>

防止SQL注入

为了防止SQL注入,您可以使用一些PostgreSQL函数:

  • quote_literal() - 正如可以预料的那样,这将引用一个文字参数值,以便在查询中安全。这不仅会阻止您Bobby Tables,还会来自Mr. O'Brien
  • quote_nullable() - 对于上述文字,但会在参数IS NULL时生成正确的代码。
  • quote_identifier() - 将引用可能导致规划人员出现问题的任何表名或列名称,例如列fromint和{{1}的表名type } {} from变为SELECT int, type, from FROM from WHERE int = type

您可以直接在SQL语句中使用这些函数,然后让PostgreSQL处理讨厌的输入。