构建查询时防止 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;
}
我通常知道如何使用 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;
}