[英]How to prevent SQL injection when dealing with dynamic table/column names?
我正在使用 jdbc PreparedStatement 进行数据插入。
Statement stmt = conn.prepareStatement(
"INESRT INTO" + tablename+ "("+columnString+") VALUES (?,?,?)");
tablename和columnString是动态生成的。
我试图参数化 tablename 和 columnString,但它们只会解析为诸如 'tablename' 之类的东西,这将违反语法。
我在网上找到了建议我查找数据库以检查有效的表名/列字符串,并将其缓存在某处(可能是哈希集)以用于另一个查询,但我正在寻找更好的性能/快速破解来解决问题,也许是一个可以解决问题的字符串验证器/正则表达式。
有没有人遇到过这个问题,你是如何解决的?
我不是一个 java 人,所以,只是一个理论。
您可以格式化动态添加的标识符或将它们列入白名单。
第二种选择要好得多。 因为
columnString
,打造特权升级是小菜一碟。因此,事先在您的代码中列出所有可能(和允许)的变体,然后根据它验证输入的值,将是最好的。
从columnString
- 由单独的列名组成。 因此,为了保护它,必须对照白名单验证每个单独的列名称,然后从它们组装一个最终的columnString
。
创建一个为您生成 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]));
作为对@Anders 回答的详细说明,不要直接使用输入参数作为名称,而是保留一个将一组允许的输入映射到实际表名的属性文件(或数据库表)。
这样,任何无效的名称都不会导致有效的 SQL(并且可以在生成任何 SQL 之前被捕获)并且实际名称在应用程序之外永远不会知道,因此更难猜测什么是有效的 SQL 语句。
我认为,最好的方法是从数据库或其他非用户输入中获取表名和列名,然后在准备好的语句中使用参数。
我们可以应用多种解决方案。
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];
注意:在执行此操作之前,您应该使用此特殊字符(`、"、[、])清理您的数据
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.