使用预准备语句 + sql 查询的动态列名,变量包含 's

Ama*_*man 4 java mysql sql jdbc

我的查询

attributes.replace(" ' ", "");
//also used SET "+attributes+" 
String sql;
sql = "UPDATE diseaseinfo"
        + " SET ?=?"
        + "WHERE companyname = 'mycom' && diseaseName =?";

PreparedStatement preparedStmt = connects.prepareStatement(sql);
preparedStmt.setString(1, attributes);
preparedStmt.setString(2, attrData);
preparedStmt.setString(3, medname);
System.out.println(preparedStmt);
Run Code Online (Sandbox Code Playgroud)

它给了我一个错误,因为查询在字符串中设置了列名,所以它在原因上变成这样

 UPDATE diseaseinfo SET 'causes'='abc' WHERE companyname = 'mycom'  and diseaseName ='fever'
Run Code Online (Sandbox Code Playgroud)

通过这个问题我知道我不能通过准备好的语句添加动态列:https : //stackoverflow.com/a/3136049/7794329

现在,真正的问题出现了:假设我是否会使用一个简单的更新查询,比如这个问题:jdbc dymanic sql query with variable containsg 's

它说你不能在你的简单 sql 查询中输入带有 's 的值,因为它会再次使查询语法错误,例如:

SELECT * FROM diseaseinfo WHERE diseaseName = 'Adult Still's disease' AND name = 'add';
Run Code Online (Sandbox Code Playgroud)

在这里它不会执行,因为 ' 's on 'Adult Still's

那么它不适用于简单的查询。我现在该怎么办?用什么?在查询中设置动态列并处理 's。

我不担心 SQL 注入,因为我在本地工作。我只想执行我的查询。

spe*_*593 5

对。我们不能提供标识符作为绑定参数。列的名称必须是 SQL 文本的一部分。

我们可以像这样动态地将列的名称合并到 SQL 文本中:

  sql = "UPDATE diseaseinfo"
      + " SET `" + colname + "` = ?"
      + " WHERE companyname = 'mycom' AND diseaseName = ?";
Run Code Online (Sandbox Code Playgroud)

并为剩余的两个绑定参数提供值

  preparedStmt.setString(1, attrData);
  preparedStmt.setString(2, medname);
Run Code Online (Sandbox Code Playgroud)

并且您对 SQL 注入的关注是完全正确的。

在值提供为绑定值,单引号attrDatamedname将不再是一个问题,在SQL注入方面。

但是,如果我们不能保证将变量包含在语句中是“安全的” ,那么我提供的示例容易通过将 colname变量合并到 SQL 文本colname中。

所以我们需要给colname“安全”赋值。

我们可以使用几种方法来做到这一点。最安全的是“白名单”方法。代码可以确保colnamecolname包含到 SQL 文本之前,只将特定的允许“安全”值分配给, 。

作为一个简单的例子:

  String colname;
  if (attributes.equals("someexpectedvalue") {
      colname = "columnname_to_be_used";
  } else if (attributes.equals("someothervalid") {
      colname = "valid_columname";
  } else {
     // unexpected/unsupported attributes value so
     // handle condition or throw an exception 
  }
Run Code Online (Sandbox Code Playgroud)

更灵活的方法是确保反引号字符不会出现在colname. 在该示例中,通过将其括在反引号中来对 的值colname进行转义。因此,只要反引号字符没有出现在 中colname,我们就会防止提供的值被解释为标识符以外的任何内容。

对于使用硬编码反引号字符的更通用(和复杂)的方法,我们可以考虑使用类的supportsQuotedIdentifiersgetIdentifierQuoteString方法java.sql.DatabaseMetaData


(在 OP 代码中,我们没有看到 内容的数据类型attributes。我们看到了对名为 的方法的调用replace,以及提供给该方法的参数。假设它attributes是一个字符串,并且应该是一个列名,完全不清楚为什么我们会在字符串中包含“空格单引号空格”,或者为什么我们需要删除它。除此之外,这个答案没有解决这个问题。)