24

我在用着

  1. jdbcTemplate 建立与 mySQL DB 的 JDBC 连接
  2. 准备好的语句以尽可能保护自己免受 SQL 注入攻击
  3. 需要接受来自用户的请求以对十几个不同列中的任何一个上的数据进行排序
  4. 以下声明

    jdbcTemplate.query("SELECT * FROM TABLE1 ORDER BY ? ?", colName, sortOrder);
    

当然这不起作用,因为变量绑定不应该指定列名,而只是指定查询中表达式的参数值。

那么......人们如何解决这个问题?只是在 Java 代码中进行排序似乎是一个简单的解决方案,但是因为我得到了一个用于列排序的变量字符串,以及一个告诉我排序顺序的变量……这是一个丑陋的比较器条件覆盖。这似乎应该是一个常见的问题,用一个常见的模式来解决它......

4

3 回答 3

24

占位符?只能用于参数值,但不能用于列和排序方向。因此,如这里所指出的那样,执行此操作的标准方法是使用String#format()或类似的东西将您的列名和顺序值附加到您的查询中。

另一种选择是使用 Spring Data JPA,您可以在其中为您的方法提供一个Sort类型的实例作为参数,该实例可以包含数据库排序所需的所有信息。

于 2012-09-14T19:02:36.927 回答
2

我只是将列名和顺序连接到 SQL 查询,但只有在

  1. 验证列名和顺序在此上下文中是否有效。
  2. 对它们进行消毒以应对任何SQL 注入攻击的尝试。

与将结果获取到应用程序层并在此处进行排序相比,我觉得这很有效。

于 2012-09-14T18:48:33.533 回答
2

我的建议是键和列的映射。这是一个安全的解决方案。

一开始,我们以最简单的方式启动我们的地图。为方便起见,我重载了 get(Obiect key)方法以在失败的情况下返回默认列(“fullName”)。这将防止 SqlExeption。

    static Map<String,String> sortCol;
{
    sortCol = new HashMap<String, String>(){
        {//Enter all data for mapping
            put("name","fullName");
            put("rok","year");
            put("rate","likes");
            put("count-rate","countRate");

        }
        /**
         * 
         * @param key for column name
         * @return column name otherwise default "fullName"
         */
        @Override
        public String get(Object key) {
            String col =super.get(key);
            return null==col?"fullName":col;
        }
    };
}

这是一个简单的使用示例。

String sqlQuery= "Select \"fullName\",year,likes,count-rate, country ..."+
 "from  blaBla..."+
 "where blaBla..."+
 "order by "+sortCol.get("keySort") "\n"; // keySort can have the value name, count-rate etc .. 

顺便说一句,您永远不应该在用户界面中透露列的真实名称,例如 REST 或 SOAP 等……对于攻击者来说,这是一个很大的帮助。

于 2018-07-31T19:27:30.630 回答