PreparedStatement的使用;可能容易受到 SQL 注入(使用 JDBC)

This use of PreparedStatement; can be vulnerable to SQL injection (with JDBC)

我的 sql 查询如下所示:

String sqlAlloc = " select %1$s from %2$s "
  + "where plot_fk in (%3$s) and plot_fk between ? and ? "
  + "and f001=? "
  + "and repdate=TO_CHAR(TO_DATE(?,'YYYYMMDD'), 'DD-Mon-YY') "
  + "and reportname = ? and change_status in (0,2,6,8,9)";
if (!cond.isEmpty()) {
                sqlAlloc += " and C007=?";
            }
if (tableName.getKey().equals(ALLOC_PENSIONFUNDS)) {
  sqlAlloc += " group by REPDATE, F001, C007, REPORTNAME, COLNAME, ROWNAME";
            }
List<String> values = Arrays.asList(tableName.getValue().split(","));
String sqlAllocFormatted = String.format(sqlAlloc,
  values.stream().collect(Collectors.joining(",")),
  jdbcUsernameMaster + "." + key,
  plotFkMasterPublicList.stream()
    .collect(Collectors.joining(",")));
try (final Connection conn = ds.getConnection();
     final PreparedStatement stmtAlloc =
       conn.prepareStatement(sqlAllocFormatted);) {
  ...

当我使用 sonarqube 扫描我的代码时,我收到以下信息: PreparedStatement的使用;可能容易受到 SQL 注入(使用 JDBC)

我不太明白 sql 查询有什么问题以及如何解决这个问题?

漏洞在于您使用 String.format 将内容注入查询字符串。如果 values/tableNamejdbcUsernameMasterkeyplotFkMasterPublicList 的值来自不受信任的来源,那么这可能是 [=21 的潜在来源=]注入.

要解决此问题,您需要不使用 String.format,而是使用静态查询字符串,或者您需要确保您的值不是来自不受信任的来源(例如用户输入、外部服务等) ,然后有意识地将警告抑制为误报。

SQL 注入在这种特殊情况下确实很难利用,但如果您知道执行的查询并且 plotFKMAsterPublicList 可以被操纵,您可以创建一个“错误的查询”。 以下是基于您的原始代码的示例:

        String sqlAlloc = " select %1$s from %2$s "
            + "where plot_fk in (%3$s) and plot_fk between ? and ? "
            + "and f001=? "
            + "and repdate=TO_CHAR(TO_DATE(?,'YYYYMMDD'), 'DD-Mon-YY') "
            + "and reportname = ? and change_status in (0,2,6,8,9)";
    List<String> values = Arrays.asList("col1,col2".split(","));
    List plotFkMasterPublicList= new ArrayList<>();
    plotFkMasterPublicList.add("plot1");
    plotFkMasterPublicList.add("plot2");
    plotFkMasterPublicList.add("plot3) union all select col1,col2 from user.table union all select  col1,col2 from user.table where (1=1 ");
    String sqlAllocFormatted = String.format(sqlAlloc,
            values.stream().collect(Collectors.joining(",")),
            "user" + "." + "table",
            plotFkMasterPublicList.stream()
                    .collect(Collectors.joining(",")));

    System.out.println(sqlAllocFormatted);

感谢@MarkRotteveel 的建议,你可以查询任何你想要的,看这些例子:

        String sqlAlloc = " select %1$s from %2$s "
            + "where plot_fk in (%3$s) and plot_fk between ? and ? "
            + "and f001=? "
            + "and repdate=TO_CHAR(TO_DATE(?,'YYYYMMDD'), 'DD-Mon-YY') "
            + "and reportname = ? and change_status in (0,2,6,8,9)";
    List<String> values = Arrays.asList("* from any_table -- col1,col2".split(","));
    List plotFkMasterPublicList= new ArrayList<>();
    plotFkMasterPublicList.add("plot1");
    plotFkMasterPublicList.add("plot2");
    String sqlAllocFormatted = String.format(sqlAlloc,
            values.stream().collect(Collectors.joining(",")),
            "user" + "." + "table",
            plotFkMasterPublicList.stream()
                    .collect(Collectors.joining(",")));

    System.out.println(sqlAllocFormatted);