sql - 如何安全地允许用户定义的 SQL 查询?

标签 sql sql-injection sql-parametrized-query

我希望允许用户使用一些相当灵活的标准来查询数据库。我可以使用以下内容:

String slqCmdTxt = "SELECT * FROM TheTable WHERE " + userExpression;

但是,我知道这对 SQL 注入(inject)很开放。使用参数很好,但我看不到允许非常灵活的查询的方法。

我怎样才能允许灵活的数据库查询而不让自己接受 SQL 注入(inject)?

更多细节:

确实有两个表,一个具有属性的主表和一个辅助表。一份主记录可能有许多属性。我们想查询两个表中的值。结果被处理成比简单的表格 View 更具可读性的报告。数据由 C# 程序编写,但当前方向是从用 Java 编写的组件中查询表。

所以我需要一种方法来提供用户输入,然后安全地构建查询。对于一组有限的输入,我编写了代码来使用给定的输入和参数值构建查询字符串。然后,我将输入值添加为参数。这导致了复杂的字符串 catination,很难更改/扩展。

现在我正在使用Java,一些搜索已经出现了像jOOQ这样的SQL语句构造库......

最佳答案

准备好的语句和输入清理
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. sanitizer
假设我们有两组表的列,用户也可以输入列名和值。

而不是像这样未经过滤的输入:
字符串查询 = "从 table1 WHERE 中选择 col1、col2、col3 吗?";
使用一些过滤器。过滤器可以是任何东西。可能是一些字符串函数或字符串比较或输入变量类型检查或任何东西。

案例1:
假设用户可以使用“col1”列进行过滤,并且它是“整数”或“数字”类型,我们可以使用正则表达式过滤输入以查看其中是否有任何特殊字符:
^[0-9]*$
案例2:
检查输入的列名是否有效。
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

最后说明:
那么,在所有这些预防措施之后,您动态生成的查询是否安全?安全得多,但你不能保证。有很多问题使您的数据库容易被注入(inject)。

关于sql - 如何安全地允许用户定义的 SQL 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11462011/

相关文章:

sql - postgresql - 将单行更改为多行

php - 乘以 1 是清除数值以防止 sql 注入(inject)的安全方法吗?

spring for mongodb转义参数以避免SQL注入(inject)

Python MYSQL 更新语句

php - 在带有 PDO 的 PHP 中,如何检查最终的 SQL 参数化查询?

sql - 在多个 OR 条件下连接 2 个表

java - 带返回列表 hibernate 的调用过程

c++ - SqlQuery 一个命名占位符多次

mysql - 我如何安全地让用户在 MySQL 和 PDO 中构建 WHERE 子句?