这两个函数都经过清理/安全,可以防止 SQL 注入吗?例如,请考虑以下情况:
@SqlUpdate("INSERT INTO <tableName> (<columns>) VALUES (<values>)")
public abstract void addRowToDataset(@Define("tableName") String tableName, @Define("columns") String columns, @BindIn("values") Collection<Object> values);
我目前的理解是,
@define
字面上将字符串按原样插入到查询中,但@bind
进行清理。因此,如果我们控制 columns
和 tableName parameters
并且只有 values
参数是用户输入,那么我们应该没问题。
我遇到了同样的问题,发现答案出奇地难以找到。一位同事告诉我,这只是上一代编程人员的常识,所以随着软件的发展,它的文档可能被遗忘了。
事实上,Oracle的绑定和定义乍一看似乎很有希望,但完全具有误导性,因为它的“定义”是指设置检索结果的引用,这与JDBI中的含义完全不同。
如果我的同事是正确的,这就是他们的实际含义:
@Define
用于常量,并插值格式 <field>
。@Bind
用于变量,并插入格式 :field
(“命名参数”)。你是对的:绑定的副作用是发生清理。@BindIn
用于列表,并插入格式 (element IN (<field>))
。这些元素也经过消毒。我的错误是对
<field>
参数使用 @Bind
格式,这导致插值始终为空字符串。
在最受好评的答案之上。根据我的测试和解释,我只想补充一点:
WHERE
和 VALUES(...)
@SqlQuery("SELECT * FROM $table ORDER BY <orderByWinsOrPlays>")
fun getPlayerRankings(@Define orderByWinsOrPlays: String)
将
<orderByWinsOrPlays>
替换为 :orderByWinsOrPlays
并将 @Define
替换为 @Bind("orderByWinsOrPlays")
不起作用,但不会引发错误。反复测试这两个选项使我得出这个结论。并且用@Define注释的类型参数最好应该是一个原始对象,否则不起作用。对于复杂的对象,使用@BindBean
@Bind
用于 JDBC 准备语句 的参数。在 JDBI 中,参数在字符串中表示为 :var
。参数仅出现在查询的某些部分,通常作为 WHERE
子句的一部分,例如SELECT * FROM Foo WHERE bar = :bar
,或在 VALUES()
的 INSERT
中。例如,它们通常不能用于指定要从中选择的表。由于 JDBI 在处理参数时在幕后使用 PreparedStatement
,因此可以缓解 SQL 注入。
@Define
用于JDBI 字符串模板中的属性。在 JDBI 中,它们在字符串中表示为
<var>
。它们可以出现在 SQL 中的任何位置,甚至出现在预准备语句不支持的位置,例如
SELECT name FROM <table>
。
@Define
似乎是为了动态构建查询,但考虑到意外 SQL 注入的风险,应该谨慎使用。