ResultSet update{ColumnType} 方法容易受到 SQL 注入的攻击吗?

Are ResultSet update{ColumnType} methods vulnerable to SQL injection?

A​​ppScan source 进行的安全扫描在以下代码的 uprs.updateString 行标记必须验证输入 (Validation.Required):

    PreparedStatement statement = 
        conn.prepareStatement (query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
    ...
    ResultSet uprs = statement.executeQuery ();
    ...
    // Update DB ColumnA with input coming from client
    uprs.updateString ('ColumnA', unvalidatedUserInput);
    ...
    // Updates the underlying database
    uprs.updateRow();

我认为这背后的意图是避免 SQL 注入攻击,但我不确定在那种情况下是否可行。

问题:SQL 注入攻击是否可能通过这些 JDBC 方法进行? JDBC 是如何在幕后实现的?这会是 AppScan 报告的另一个误报吗?

我不确定 bluemix-app-scan,但我在这里提供我的解释。 (这是我根据以下测试和粘贴的代码做出的假设

我运行一个测试代码来检查这个(在H2 DB
testName 字符串的值:(select 'sqlInjection' from dual)

  1. 使用 createStatement (不安全):

    String query = "update TEST_TABLE set TEST_CHAR = " + testName + " where ID = 1";
    Statement statement = connection.createStatement();
    statement.executeUpdate(query);
    

    输出: TEST_CHAR 在数据库中是 sqlInjection.

  2. 使用 createStatementResultSet (在 H2 数据库中安全):

    String query = "select * from TEST_TABLE where ID = 1";
    Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
    ResultSet executeQuery = statement.executeQuery(query);
    executeQuery.next();
    executeQuery.updateString("TEST_CHAR", testName);
    executeQuery.updateRow();
    

    输出: 令人惊讶的是 TEST_CHAR 在 DB 中是 (select 'sqlInjection' from dual) .

  3. 使用 PreparedStatement (安全):

    String query = "update TEST_TABLE set TEST_CHAR = ? where ID = 1";
    PreparedStatement statement = connection.prepareStatement(query);
    statement.setString(1, testName);
    statement.executeUpdate();
    

    输出: 预期 - DB 中的 TEST_CHAR 是 (select 'sqlInjection' 来自 dual).

  4. 使用 ResultSet of prepareStatement (在 H2 数据库中安全):

    String query = "select * from TEST_TABLE where ID = 1";
    PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
    ResultSet uprs = statement.executeQuery();
    uprs.next();
    uprs.updateString("TEST_CHAR", testName);
    uprs.updateRow();
    

    输出: 预期 - DB 中的 TEST_CHAR 是 (select 'sqlInjection' 来自 dual).

返回问题:

Are SQL Injection attacks possible through these JDBC methods?

可能。 这取决于您使用的数据库驱动程序。
如何? : 我的结果集更新中 SQL 注入失败的原因是因为 H2 数据库在调用 ResultSet.updateRow() 时在内部使用 PreparedStatement 更新行。

public void updateRow(Value[] current, Value[] updateRow) throws SQLException {
    StatementBuilder buff = new StatementBuilder("UPDATE ");
    ...
    buff.append(" SET ");
    appendColumnList(buff, true);
    ...
    appendKeyCondition(buff);
    PreparedStatement prep = conn.prepareStatement(buff.toString());
    ...
    for (int i = 0; i < columnCount; i++) {
       ...
        v.set(prep, j++);
    }
    setKey(prep, j, current);
    int count = prep.executeUpdate();
    ...
}

我不确定 java 中的所有数据库驱动程序是否都使用 preparedStatement 实现了 updateRow() 方法。但是很明显,这留给了驱动程序,如果 bluemix 建议您在此处添加验证,我建议您遵循 :)

How does JDBC implements this under the scenes?

好吧,如上所示,这是特定于驱动程序的。然而,关于 PreparedStatement 如何处理它超过 here 有一个很好的解释。

Would this be another false positive reported by AppScan?

我不认为这是误报(但在像 H2 DB 这样的情况下它是)但你永远不会知道是否所有数据库驱动程序都安全地实现了这一点。

编辑-
甚至 PostgreSQL 和 MySQL 也使用 PreparedStatement 来处理这个问题。

public synchronized void updateRow() throws SQLException
{
    ...
    updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
    ...  
    updateStatement.executeUpdate();
    ...
}