Java SQL安全地检查列是否存在

时间:2017-04-20 18:44:38

标签: java postgresql jdbc

我需要拥有动态SQL,它接受来自用户的表名和列名,并在查询中使用它们。现在我用

做到这一点
public Object doSearch(String table, List<String> columns) {
//... some logic
String.format("SELECT %s from %s", String.join(", ", columns), table");
//... some execution and return
}

源不受信任,因此我想要对表名和列名进行白名单,但该列表会更改。有效表的列表严格地是my_schema上的表的列表,有效列的列表严格地是该特定表上的列。

我在SO周围搜索并找到了类似的解决方案:

private boolean validate(String tableName, List<String> columnNames) throws SQLException {
    return tableExist(tableName) && columnNames.stream().allMatch(cn -> columnExistsOnTable(tableName, cn));
}
private boolean tableExist(String tableName) throws SQLException {
    try (ResultSet rs = connection.getMetaData().getTables(null, schema, tableName, null)) {
        while (rs.next()) {
            String tName = rs.getString("TABLE_NAME");
            if (tName != null && tName.equals(tableName)) {
                return true;
            }
        }
    }
    return false;
}

private boolean columnExistsOnTable(String tableName, String columnName) {
    try (ResultSet rs = connection.getMetaData().getColumns(null, schema, tableName, columnName)) {
        while (rs.next()) {
            String tName = rs.getString("COLUMN_NAME");
            if (tName != null && tName.equals(tableName)) {
                return true;
            }
        }
    } catch (SQLException sqle) {
        return false;
    }
    return false;
}

这样安全吗?

1 个答案:

答案 0 :(得分:0)

对于这些方法中的每一种,您可以在初始化方法中执行此操作一次并缓存表/列名称,这样您就不必每次都进行数据库检查......这样的事情:

private Map<String, Set<String>> tableColNames = new HashMap();


    private void initCache(){
       // build the cache


  // get all tables 
   // get all columns
   // add tables and columns to the map 
}


private boolean tableExist(String tableName) throws SQLException {
    return tableColNames.containsKey(tableName);
}

private boolean columnExistsOnTable(String tableName, String columnName) {
   if(tableExist(tableName)){
     return   tableColNames.get(tableName).contains(columnName);
   } else {
     return false;
   }

}
// could make a method for checking a list of Strings too...
// return tableColNames.get(tableName).containsAll(columnName);

https://docs.oracle.com/javase/7/docs/api/index.html?java/sql/ResultSetMetaData.html