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

Fortify flagging query as sqlInjection when passing in parameters to a method

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

public List<String> getNamesFromId(List<Long> 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<String> namesList = new ArrayList<String>();

        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 注入说 "invokes a SQL query built using input potentially coming from an untrusted source. This call could allow an attacker to modify the statement's meaning or to execute arbitrary SQL commands."

这是因为这是一个 public 面向方法,我们正在为预准备语句的 IN 部分传递参数吗?如果是这样,我们怎样才能做得更好?还是fortify误报?

这是误报,你做对了。

有些框架可以帮助您解决这个问题(例如 Spring 的 NamedParameterJdbcTemplate,但它们基本上在幕后做同样的事情。

静态分析器可能发现您正在通过连接字符串构建查询,或者以某种方式涉及输入的大小,并将其标记为危险(此处仅猜测)。


附带说明一下,一个与 SQL 注入无关的潜在问题是您只能使用这些参数中的特定数量(依赖于数据库)- AFAIK 在 Oracle 中限制为 1000, Teradata 大约有 2000 个,其他的不确定。如果您需要在该 IN 子句中放置许多值,则需要使用不同的方法,例如使用临时 table 或以较小的批次执行查询并将结果合并到 Java.