将参数传递给方法时将标记查询强化为 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的主要内容,如果未能解决你的问题,请参考以下文章