构建查询时防止 SQL 注入

Prevent SQL injection when building query

我通常知道如何使用 preparedStatements 来防止它,但现在我有这样一种方法来构建查询。例如 Java:

private String buildQuery(String where) {
    String query = "SELECT id, name FROM someTable";
    if(where.length() > 0) {
        query = query + " WHERE " + where;
    }
    return query;
}

'where' 字符串是这样的 'variable = value'。我怎样才能在这里防止它?我考虑过分别传递变量和值,使用它们创建准备好的语句,然后以某种方式将该准备好的语句作为字符串返回,但我不确定。

这不特定于任何一个数据库 API。

TL;DR: 不要绕过 "SQL fragments"。

与其传递 select 语句的完整子句,或将(子)表达式添加到 select 子句中,不如传递将用户数据与标识符分开的组件。

这种情况下不要传name = value,分开传。然后验证 name 是 table 的有效列,并为 value 部分生成一个参数。

因此,伪代码(我的Java生锈了):

function BuildCommand(string column, object value) {
  if !IsValidColumn("theTable", column)) throw InvalidOperation(...)

  string sql = "Select column from theTable where " + column + " = @p0";

  SqlCommand cmd = new SqlCommand(sql);
  cmd.Parameters.Add("@p0", value);

  return cmd;
}

您可以使用映射来传递您的值并构建 preparedStatement。检查下面的代码它应该类似于那个逻辑

public static PreparedStatement buildQuery(String where,Map<Integer, String> cond)
        throws SQLException {

    PreparedStatement stat = null;

    String query = "SELECT id, name FROM someTable " + where;

    try {
        stat = con.prepareStatement(query);

        for (Map.Entry<Integer, String> e : cond.entrySet()) {
            stat.setString(e.getKey(), e.getValue());
        }
    } catch (SQLException e ) {
        // Handle ex
    } finally {

    }
    return  stat;
}


public static void main(String[] a) throws SQLException {
    Map<Integer,String> cond =new HashMap<Integer, String>();
    cond.put(1,"val22");
    cond.put(2,"val2");


    buildQuery("col1 = ? and col2= ?", cond);
}

我的建议是,如果您在参数中有一个 where 子句数组,并将函数重写为:

private String buildQuery(String[] where) {
    String query = "SELECT id, name FROM someTable";
    query = query + " WHERE "
    for(int i = 0; i < where.length; i++) {
        if(i > 0){
            query = query + " AND "
        }
        query = query + w + " = ?";
    }
    return query;
}