我不确定 bluemix-app-scan,但我在这里提供我的解释。(这是我基于以下测试和粘贴代码的假设)
我运行了一个测试代码来检查testName String的这个(在H2 DB中)
值:(select 'sqlInjection' from dual)
使用(不安全):createStatement
String query = "update TEST_TABLE set TEST_CHAR = " + testName + " where ID = 1";
Statement statement = connection.createStatement();
statement.executeUpdate(query);
输出:数据库中的 TEST_CHAR是sqlInjection。
使用(在 H2 DB 中安全ResultSet
)createStatement
:
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)。
使用(安全):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)。
使用(在 H2 DB 中安全ResultSet
)prepareStatement
:
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();
...
}