我需要拥有动态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;
}
这样安全吗?
答案 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