0

例如,在我的代码中有一些地方,我的源查询中的问号数量会根据数据的某些特征而变化。我没有将用户数据放在 SQL 中,但我正在调整问号的数量。做到这一点的唯一方法是使用字符串连接/格式化/等,这会触发 Findbugs 的警告:

准备好的语句是从非常量字符串生成的

是否有一种(非代码异味)方法可以自动生成 SQL 而不会让 Findbugs 认为这是一个漏洞?

我现在拥有的示例代码:

final static String BASE_SQL = "SELECT * FROM customers WHERE id IN (questionMarkPlaceholder)";

[...]

final String questionMarks = "?" + StringUtils.repeat(", ?", customers.length - 1);
final String sql = BASE_SQL.replaceFirst("questionMarkPlaceholder", questionMarks);
statement = conn.prepareStatement(sql);

int counter = 1;
for (Customer customer : customers) {
    statement.setString(counter, customer.getId());
    counter++;
}

resultSet = statement.executeQuery();
4

2 回答 2

1

有一些持久性 api 不需要为动态参数数量手动连接字符串。 Hibernate CriteriaQuerydsl有 DSL 可以避免这个问题。

在您的特定情况下,查询不容易受到攻击,因为这些值不是来自用户输入。FindBugs 警告可以被认为是误报。如果您确定这些值可以由远程用户控制,则可以使用 ESAPI 实用程序类Encoder.encodeForSQL

于 2013-10-08T22:39:24.580 回答
0

我见过的最好的方法是使用一些预定义的查询(这可能适用于您的情况,也可能不适用)。将参数占位符与准备好的语句一起使用有两个优点。一个是防止 SQL 注入,但您也可以从重用已编译的查询中获得性能优势。该方法定义了几种批量大小:

private static final String QUERY_SIZE_SINGLE = "SELECT * FROM customers WHERE id=?";
private static final String QUERY_SIZE_SMALL = "SELECT * FROM customers WHERE id IN (?,?,?)";
private static final String QUERY_SIZE_MEDIUM = "SELECT * FROM customers WHERE id IN (?,?,?,?,?,?)";
private static final String QUERY_SIZE_LARGE = "SELECT * FROM customers WHERE id IN (?,?,?,?,?,?,?,?,?,?,?,?)"
private static final int SINGLE = 1;
private static final int SMALL = 3;
private static final int MEDIUM = 6;
private static final int LARGE = 12;

//in your query code...
int remainingCustomers = customers.size();
while (remainingCustomers > 0){
  PreparedStatement ps;
  if (remainingCustomers > LARGE){
     ps = con.prepareStatement(QUERY_SIZE_LARGE);
    //loop through the first LARGE parameters and set them
    remainingCustomers -= LARGE;
   }else if (remainingCustomers > MEDIUM){
   ///so on
   ...
   }//end if
    //execute the statement
    //add results to a temporary list holding the results
}//end while

基本上这里的想法是根据客户数量对查询进行批处理。我选择的查询大小是完全任意的。理想情况下,您会根据应用程序的常用值来选择这些数字,以最大程度地减少数据库往返次数。这种方法允许您利用准备好的语句的好处,同时最大限度地减少数据库往返(即缓慢的 IO 操作)。

注意:我希望我能将这种方法归功于我,但我在寻找类似问题的答案时发现了它,并且不再记得我在哪里找到它......

于 2013-10-08T22:55:27.160 回答