使用JOOQ,我还需要什么来阻止sql注入

时间:2017-11-08 15:04:39

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

这是怎么回事,因为我在这里专门询问JOOQ?

我在我的JAVA项目中使用JOOQ来处理我的所有PostgreSQL查询。我在this文章中读到JOOQ使用预准备语句来执行所有查询。

  1. 假设在执行查询时我不需要担心SQL注入或用户输入,这是否安全?

  2. 在将用户输入转交给JOOQ之前,我不需要担心转义用户输入吗?

  3. 在旁注中,我的数据库在获取用户输入时存在哪些其他漏洞(除了那些由准备好的语句解决的漏洞),我应该注意哪些?

2 个答案:

答案 0 :(得分:1)

1)是的,只要您正确使用提供的API即可。仍然可以注入简单的SQL查询,所以要小心。

  

jOOQ API中允许普通(未转义,未处理)SQL的所有方法都在其相关的Javadoc中包含警告消息

// This query will use bind values, internally.
create.fetch("SELECT * FROM BOOK WHERE ID = ? AND TITLE = ?", 5, "Animal Farm");
// This query will not use bind values, internally.
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = 'Animal Farm'");

请参阅此处的JOOQ文档以获得更深入的解释:https://www.jooq.org/doc/3.9/manual/sql-building/bind-values/sql-injection/

2)不,见上文。

3)除此之外,请注意一般数据库安全问题,例如用户身份验证/角色以及以非加密格式存储敏感数据等

答案 1 :(得分:0)

无论您使用何种语言和框架,始终都可以编写不安全的查询。

将变量连接到SQL的简单方法为SQL注入创造了机会:

String unsafeString = "O'Reilly";
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = '"+unsafeString+"'");
// results in SQL syntax error because of unmatched ' marks

仅使用准备好的查询不会对安全查询进行不安全的查询。

使用参数将动态值与SQL查询分开。它们在执行时在RDBMS中组合。参数无法导致SQL注入漏洞。

String unsafeString = "O'Reilly";
create.fetch("SELECT * FROM BOOK WHERE ID = 5 AND TITLE = ?", unsafeString);
// still OK

使用参数时,不需要对变量进行任何转义。实际上,你一定不能,,因为你的数据中最终会出现转义符号。

参数适用于将Java变量组合到SQL查询中,但仅限于SQL标量值。也就是说,您通常在SQL中使用带引号的字符串文字,带引号的日期文字或数字文字,您可以用参数占位符替换它。

但是你不能在SQL中使用其他任何参数:

  • 表名
  • 列名
  • 值列表,例如IN ( ... )谓词 - 您必须在列表中为每个值使用一个?占位符。
  • SQL表达式
  • SQL关键字

您可能会喜欢我的演示文稿SQL Injection Myths and Fallaciesvideo)或我的书SQL Antipatterns: Avoiding the Pitfalls of Database Programming

来自@rehas的评论:

实际上,使用预准备语句意味着您隐式使用参数。我在上面展示了一个例子(我的第一个例子),它将一个不安全的变量连接到一个SQL字符串,然后再发送到prepare()。

一旦SQL字符串到达​​RDBMS服务器,就无法知道字符串的哪些部分是合法的,哪些部分是从不安全的变量连接起来的。它看到的只是一个包含SQL语句的字符串。

使用参数的目的是使(可能不安全的)变量与SQL字符串分开。在RDBMS服务器中,解析了仍然包含?等参数占位符的SQL字符串。解析后,它将不再被解析,因此将“O'Reilly”这样的字符串绑定到参数占位符是安全的,而不会产生引号不匹配或任何内容的风险。保证在SQL执行中将参数视为单个值,即使参数的值包含将改变查询解析方式的字符,如果在准备之前已包含 ()。

使用prepare()并不意味着你总是使用参数。

准确地说,使用参数需要使用prepare()和execute()作为单独的步骤。但是有些框架会为您完成这两个步骤。我确定你是否要阅读jOOQ源代码,你会看到它。