1

AppScan 源进行的安全扫描在以下代码的行中标记输入必须经过验证 (Validation.Required) uprs.updateString

    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 报告的另一个误报吗?

4

1 回答 1

3

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

我运行了一个测试代码来检查testName String的这个(在H2 DB中)
值:(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. 使用(在 H2 DB 中安全ResultSetcreateStatement

    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();
    

    输出:令人惊讶的是,DB 中的 TEST_CHAR 是(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' from dual)

  4. 使用(在 H2 DB 中安全ResultSetprepareStatement

    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' from dual)

返回问题:

是否可以通过这些 JDBC 方法进行 SQL 注入攻击?

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

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中的所有数据库驱动程序是否都updateRow()使用了方法preparedStatement。但是很明显,这留给了驱动程序,如果 bluemix 建议您在此处添加验证,我建议您遵循 :)

JDBC 是如何在幕后实现的呢?

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

这会是 AppScan 报告的另一个误报吗?

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

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

public synchronized void updateRow() throws SQLException
{
    ...
    updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
    ...  
    updateStatement.executeUpdate();
    ...
}
于 2017-01-10T21:42:57.687 回答