JDBI 如何在防止 SQL 注入的同时动态创建 WHERE 子句?
JDBI How can I dynamically create a WHERE clause while preventing SQL Injection?
我想动态过滤 JDBI 查询。
参数列表通过 REST 从 UI 传递,例如
http://localhost/things?foo=bar&baz=taz
http://localhost/things?foo=buz
它(笨拙地)构建(Jersey @Context UriInfo::getQueryParameters -> StringBuilder)是这样的:
WHERE foo=bar AND baz=taz
并传递给 JDBI,如下所示:
@UseStringTemplate3StatementLocator
public interface ThingDAO {
@SqlQuery("SELECT * FROM things <where>)
List<Thing> findThingsWhere(@Define("where") String where);
}
据我所知,当前的实现很容易受到 SQL 注入的攻击。
我显然可以清理列名,但不能清理值。 1
必须有一种更优雅且 SQL 防注入的方式来做到这一点。
使用参数化查询。 Here 是他们的 jdbi 页面。
参数化查询是在大多数设置中防止 sql 注入的方法。
您可以动态创建 where 语句,但保留参数名称而不是值,它们将在以后以安全的方式绑定。
您可能会对这一点特别感兴趣,因为您的参数是动态的:
@BindingAnnotation(BindSomething.SomethingBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindSomething
{
public static class SomethingBinderFactory implements BinderFactory
{
public Binder build(Annotation annotation)
{
return new Binder<BindSomething, Something>()
{
public void bind(SQLStatement q, BindSomething bind, Something arg)
{
q.bind("ident", arg.getId());
q.bind("nom", arg.getName());
}
};
}
}
}
我从未使用过 jdbi,所以我不能 100% 确定您必须做什么,但看起来 q.bind(...) 方法正是您想要的。
我想到了这个:
public class WhereClause {
public HashMap<String, String> queryValues; // [<"foo","bar">, <"baz","taz">]
public String preparedString; // "WHERE foo=:foo AND bar=:baz"
}
通过自定义 Binder 绑定 BindWhereClause
:
@BindingAnnotation(BindWhereClause.WhereClauseBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindWhereClause {
class WhereClauseBinderFactory implements BinderFactory {
public Binder build(Annotation annotation) {
return new Binder<BindWhereClause, WhereClause>() {
public void bind(SQLStatement q, BindWhereClause bind, WhereClause clause) {
clause.queryValues
.keySet()
.forEach(s -> q.bind(s, clause.queryValues.get(s)));
}
};
}
}
}
以及 @Define
和 @Bind
的组合:
@UseStringTemplate3StatementLocator
public interface ThingDAO {
@SqlQuery("SELECT * FROM things <where>")
List<Thing> findThingsWhere(@Define("where") String where,
@BindWhereClause() WhereClause whereClause);
}
这应该是注入证明。 (是吗?)
我想动态过滤 JDBI 查询。
参数列表通过 REST 从 UI 传递,例如
http://localhost/things?foo=bar&baz=taz
http://localhost/things?foo=buz
它(笨拙地)构建(Jersey @Context UriInfo::getQueryParameters -> StringBuilder)是这样的:
WHERE foo=bar AND baz=taz
并传递给 JDBI,如下所示:
@UseStringTemplate3StatementLocator
public interface ThingDAO {
@SqlQuery("SELECT * FROM things <where>)
List<Thing> findThingsWhere(@Define("where") String where);
}
据我所知,当前的实现很容易受到 SQL 注入的攻击。 我显然可以清理列名,但不能清理值。 1
必须有一种更优雅且 SQL 防注入的方式来做到这一点。
使用参数化查询。 Here 是他们的 jdbi 页面。
参数化查询是在大多数设置中防止 sql 注入的方法。
您可以动态创建 where 语句,但保留参数名称而不是值,它们将在以后以安全的方式绑定。
您可能会对这一点特别感兴趣,因为您的参数是动态的:
@BindingAnnotation(BindSomething.SomethingBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindSomething
{
public static class SomethingBinderFactory implements BinderFactory
{
public Binder build(Annotation annotation)
{
return new Binder<BindSomething, Something>()
{
public void bind(SQLStatement q, BindSomething bind, Something arg)
{
q.bind("ident", arg.getId());
q.bind("nom", arg.getName());
}
};
}
}
}
我从未使用过 jdbi,所以我不能 100% 确定您必须做什么,但看起来 q.bind(...) 方法正是您想要的。
public class WhereClause {
public HashMap<String, String> queryValues; // [<"foo","bar">, <"baz","taz">]
public String preparedString; // "WHERE foo=:foo AND bar=:baz"
}
通过自定义 Binder 绑定 BindWhereClause
:
@BindingAnnotation(BindWhereClause.WhereClauseBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindWhereClause {
class WhereClauseBinderFactory implements BinderFactory {
public Binder build(Annotation annotation) {
return new Binder<BindWhereClause, WhereClause>() {
public void bind(SQLStatement q, BindWhereClause bind, WhereClause clause) {
clause.queryValues
.keySet()
.forEach(s -> q.bind(s, clause.queryValues.get(s)));
}
};
}
}
}
以及 @Define
和 @Bind
的组合:
@UseStringTemplate3StatementLocator
public interface ThingDAO {
@SqlQuery("SELECT * FROM things <where>")
List<Thing> findThingsWhere(@Define("where") String where,
@BindWhereClause() WhereClause whereClause);
}
这应该是注入证明。 (是吗?)