我有一个我想传递给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
。你如何解决这个问题并安全地逃离这个字符串?
答案 0 :(得分:0)
Prepared语句用于计划复杂语句一次,然后使用不同的参数值执行多次(=非常多次)。简单的陈述使用准备好的陈述没有明显的好处,因为规划它们是微不足道的。完全不支持DDL语句,因此很可能是错误的原因,尽管错误消息令人困惑。
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()
- 将引用可能导致规划人员出现问题的任何表名或列名称,例如列from
,int
和{{1}的表名type
} {} from
变为SELECT int, type, from FROM from WHERE int = type
。 您可以直接在SQL语句中使用这些函数,然后让PostgreSQL处理讨厌的输入。