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

Posted

技术标签:

【中文标题】将参数传递给方法时将标记查询强化为 sqlInjection【英文标题】:Fortify flagging query as sqlInjection when passing in parameters to a method 【发布时间】:2016-02-13 00:09:57 【问题描述】:

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

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 注入说 “调用使用可能来自不受信任来源的输入构建的 SQL 查询。此调用可能允许攻击者修改语句的含义或执行任意 SQL 命令。”

这是因为这是一个面向公众的方法,并且我们正在为准备好的语句的 IN 部分传递参数吗?如果是这样,我们怎样才能做得更好?还是fortify的虚惊一场?

【问题讨论】:

【参考方案1】:

这是一场虚惊,你的做法是对的。

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

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


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

【讨论】:

@user1623627 您还可以通过使用 IntSteam.rangeClosed().map() 来跳过 for 循环和删除解决方法来生成 ?'s 和 StringJoiner,'s 放在它们之间。 ***.com/a/18532568docs.oracle.com/javase/8/docs/api/java/util/StringJoiner.html @AlainO'Dea 好点。或者,如果在 8 之前的 Java 上,您可以使用 StringUtils.repeat() from Apache Commons(它实际上可能变得更具可读性,因此即使在 Java 8 中也值得考虑)。 FWIW pre Java 8 不应该在任何地方投入生产,因为它不再获得安全补丁。可读性是一个时间问题。如果 IntStream 习语变得普遍,那么它的优势就是在标准库中。

以上是关于将参数传递给方法时将标记查询强化为 sqlInjection的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL:将词法参数传递给存储过程

我可以在构建时将参数传递给angular-cli

执行 curl 获取的脚本时将参数传递给 bash

在编译时将参数传递给主函数

角 |导航时将参数传递给多个组件

快速将参数传递给#selector方法[重复]