我正在使用jdbc PreparedStatement进行数据插入。
Statement stmt = conn.prepareStatement(
"INESRT INTO" + tablename+ "("+columnString+") VALUES (?,?,?)");
tablename 和 columnString 是动态生成的内容。
我已尝试参数化tablename和columnString,但它们只会解析为类似'tablename'的内容,这会违反语法。
我在网上发现某个地方建议我查找数据库以检查有效的tablename / columnString,并将其缓存到某个地方(也许是一个Hashset)用于另一个查询,但我正在寻找更好的性能/快速入侵解决问题,也许是一个字符串验证器/正则表达式,可以解决问题。
有没有人遇到过这个问题,你是如何解决的?
答案 0 :(得分:1)
我不是一个java人,所以,只是一个理论。
您可以格式化动态添加的标识符或 white-list 。
第二种选择更好。因为
columnString
,可以打造特权升级。因此,要预先在代码中列出所有可能的(和允许的)变体,然后根据它验证输入的值,这将是最好的。
从columnString
开始 - 由单独的列名组成。因此,为了保护它,必须针对白名单验证每个单独的列名称,然后从它们汇编最终columnString
。
答案 1 :(得分:0)
创建一个为您生成sql字符串的方法:
private static final String template = "insert into %s (%s) values (%s)";
private String buildStmt(String tblName, String ... colNames) {
StringJoiner colNamesJoiner = new StringJoiner(",");
StringJoiner paramsJoiner = new StringJoiner(",");
Arrays.stream(colNames).forEach(colName -> {
colNamesJoiner.add(colName);
paramsJoiner.add("?");
});
return String.format(template, tblName, colNamesJoiner.toString(), paramsJoiner.toString());
}
然后使用它......
Statement stmt = conn.prepareStatement(buildStmt(tablename, [your column names]));
答案 2 :(得分:0)
作为@Anders答案的详细说明,不要直接使用输入参数作为名称,而是保留一个属性文件(或数据库表),将一组允许的输入映射到实际的表名。
这样,任何无效的名称都不会导致有效的SQL(并且可以在生成任何SQL之前捕获)并且实际名称在应用程序之外永远不会被知道,因此很难猜出什么是有效的SQL语句。
答案 3 :(得分:0)
我认为,最好的方法是从数据库或其他非用户输入中获取表名和列名,并在准备好的语句中使用其余参数。
答案 4 :(得分:0)
我们可以应用多种解决方案。
1)白名单输入验证
String tableName;
switch(PARAM):
case "Value1": tableName = "fooTable";
break;
case "Value2": tableName = "barTable";
break;
...
default : throw new InputValidationException("unexpected value provided for table name");
2)使用特殊字符绑定动态columnName(s)或tableName(s),如下所示
例如:
从`tableName`中选择`columnName`;
从“tableName”中选择“columnName”;
或
从[tableName]中选择[columnName];
注意:在执行此操作之前,您应使用此特殊字符(`,“,[,])
清理数据