对.我们不能提供标识符作为绑定参数.列的名称必须是SQL文本的一部分.
我们可以将列名称动态地合并到SQL文本中,如下所示:
sql = "UPDATE diseaseinfo"
+ " SET `" + colname + "` = ?"
+ " WHERE companyname = 'mycom' AND diseaseName = ?";
并为剩余的两个绑定参数提供值
preparedStmt.setString(1, attrData);
preparedStmt.setString(2, medname);
您完全关心SQL注入是正确的.
作为绑定值提供,就SQL注入而言,attrData和medname值中的单引号不会成为问题.
但是,如果我们不能保证将colname包含在语句中,那么我提供的示例很容易通过将colname变量合并到SQL文本中而受到攻击.
因此,我们需要为“安全”名称分配一个值.
我们可以使用几种方法来做到这一点.最安全的是“白名单”方法.该代码可以确保在将colname包含在SQL文本中之前,仅将特定的允许的“安全”值分配给colname.
作为一个简单的例子:
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
}
一种更灵活的方法是确保反引号字符不会出现在colname中.在示例中,colname的值通过将其括在反引号中进行转义.因此,只要colt中没有出现反引号字符,我们就可以防止将提供的值解释为标识符以外的任何内容.
对于使用硬编码反引号字符的更通用(更复杂)的方法,我们可以考虑使用java.sql.DatabaseMetaData类的supportsQuotedIdentifiers和getIdentifierQuoteString方法.
(在OP代码中,我们没有看到属性内容的数据类型.我们看到了对名为replace的方法的调用,以及为该方法提供的参数.假定属性是一个String,并且应该是列名,我们不清楚为什么我们在字符串中要有“空格单引号空间”,或者为什么我们需要删除它.除此提及外,此答案没有解决这个问题.)