将参数传递给方法时,将标记查询强制为sqlInjection

我们的数据库层中有一个方法,如下所示:

public List getNamesFromId(List idsList){ StringBuilder query = new StringBuilder(); query.append("Select first_name from person where id in ("); for (int pos = 0; pos < idsList.size(); pos++) { query.append("?"); query.append(","); } query.deleteCharAt(query.length() - 1).append(")"); try { conn = establishConnection(); pstmt = conn.prepareStatement(query.toString()); for (int i = 0; i < selections.size(); i++) { pstmt.setLong(i + 1, idsList.get(i)); } rs = pstmt.executeQuery(); } catch (SQLException e) { // } try { List namesList = new ArrayList(); while (rs.next()) { namesList.add(rs.getString("FIRST_NAME")); } } catch (SQLException e) { // } // close the Connection object try { rs.close(); pstmt.close(); conn.close(); } catch (SQLException e) { // } 

在我们的强化扫描期间,它将此标记为SQL注入“调用使用可能来自不受信任来源的输入构建的SQL查询。此调用可能允许攻击者修改语句的含义或执行任意SQL命令。”

这是因为这是一个面向公众的方法,我们传递准备语句的IN部分的参数? 如果是这样,我们怎样才能做得更好? 还是来自强化的误报?

这是一个误报,你正在以正确的方式做到这一点。

有一些框架可以帮助你解决这个问题(比如Spring的NamedParameterJdbcTemplate ,但它们基本上都是在做同样的事情。

静态分析器可能通过连接字符串来捕获你正在构建查询的事实,或者输入的大小以某种方式涉及,并将其标记为危险(仅在这里猜测)。


另一方面,与SQL注入无关的潜在问题是,您只能使用某些数量(与DB相关)的参数–AFAIK在Oracle中限制为1000,在Teradata中约为2000,不确定其他参数。 如果需要在IN子句中放置许多值,则需要使用不同的方法,例如使用临时表或以较小批量执行查询并在Java中合并结果。