准备好的语句和输入清理
1. 准备好的报表
Java 提供PreparedStatement来执行参数化查询。使用 Prepared Statements 构建的查询不太容易受到攻击。
例子:
我们需要做的查询:
String query = "SELECT col1, col2, col3 FROM table1 WHERE " + user_input;
使用带有参数化值的 PreparedStatement:
// write the query with "?" placeholder for the user_input
String query = "SELECT col1, col2, col3 FROM table1 WHERE ?";
// Create database connection
Connection conn = source.getConnection();
// Prepare a statement for the query
PreparedStatement stmt = conn.prepareStatement(query);
// set the placeholder with the actual user_input
stmt.setString(1, user_input);
// execute the query
ResultSet result = stmt.executeQuery(query);
够了吗?不!
即使在使用 PreparedStatement 或 createQuery(JPA 的类似方法)或任何东西之后,攻击者仍有可能通过。所以这把我们带到了这个......
正如@phil 指出的那样进行编辑,使用 PreparedStatement 确实可以阻止非法值的执行。但我仍然强烈建议对输入进行清理,因为当您期待“int”时,用户可能会输入“String”或随机特殊字符。
2. 消毒
假设我们有两组表的列,用户也可以输入列名和值。
而不是像这样未经过滤的输入: String query = "SELECT col1, col2, col3 FROM table1 WHERE ?"; 使用一些过滤器。过滤器可以是任何东西。可能是一些字符串函数或字符串比较或输入变量类型检查或任何东西。
案例1:
假设用户可以使用列“col1”进行过滤,并且它是“整数”或“数字”类型,我们可以使用正则表达式过滤输入以查看其中是否有任何特殊字符:
^[0-9]*$
Case2:
检查输入的列名是否有效。
private static final Set<String> valid_column_names
= Collections.unmodifiableSet(Stream
.of("col1", "col2", "col3")
.collect(Collectors.toCollection(HashSet::new)));
boolean is_valid = false;
if (valid_column_names.contains(user_column_input)) {
is_valid = true;
}
if(!is_valid){
throw new IllegalArgumentException("Invalid Column input");
}
String query = "SELECT col1, col2, col3 FROM table1 WHERE ?";
// prepare statements and execute
最后说明:
那么,在所有这些预防措施之后,您动态生成的查询是否安全?安全得多,但你不能保证。有很多问题使您的数据库容易被注入。