Java 私有查询方法是否会增加SQL注入攻击风险?
我曾有人指出,使用私有方法处理由单个类完成的所有查询的执行会增加SQL注入攻击的风险 此方法的示例可能如下所示(如下所示)。我省略了一些细节,以免在实施过程中分散任何人的注意力 如果您想谈论实施,请随时在评论中发表意见。安全审查没有评论该方法的内容,但主要是它不应该是自己的方法 注意,queryText是从一个受保护的静态最终字符串生成的,该字符串包含准备语句的SQL文本。PreparedStatement文本中的?是使用PreparedStatement的setString(或set which)方法设置的。在prepared语句上设置的变量以尽可能强的类型进入调用方方法 然后将queryText传递给私有方法Java 私有查询方法是否会增加SQL注入攻击风险?,java,sql,security,sql-injection,Java,Sql,Security,Sql Injection,我曾有人指出,使用私有方法处理由单个类完成的所有查询的执行会增加SQL注入攻击的风险 此方法的示例可能如下所示(如下所示)。我省略了一些细节,以免在实施过程中分散任何人的注意力 如果您想谈论实施,请随时在评论中发表意见。安全审查没有评论该方法的内容,但主要是它不应该是自己的方法 注意,queryText是从一个受保护的静态最终字符串生成的,该字符串包含准备语句的SQL文本。PreparedStatement文本中的?是使用PreparedStatement的setString(或set whic
private ResultSet executeQuery(PreparedStatement stmt) throws SQLException {
// Declare result set variable
try{
try{
// execute statement and store in variable
}
catch(SQLException se){
// log, close connection, do any special processing, rethrow se
}
}
finally{
// This finally block is here to ensure the connection closes if
// some special processing (not shown) in the other try generates a runtime exception
// close connection and statement properly
}
// return result set
}
推荐的替代方法是在执行查询的每个方法中基本上内联相同的代码
我没有将此发布到security.stackexchange.com,因为我认为它符合特定的安全编程问题
我想不出为什么将这段代码(从私有方法)复制到许多类中会增加任何保护。会吗
谢谢如果此方法执行的查询包含SQL注入所需的成分,那么不管是
private/public
方法,它都会影响
这个私有方法将由某个公共方法调用,该方法从用户(或)数据库获取输入。若输入是恶意的,私有方法无法阻止它执行
不要使用原始SQL字符串,最好使用准备好的语句。有一个中心(不重复)位置来执行查询是一个好主意。从代码可维护性和安全性的角度来看。为什么有可能多次出现问题的代码?这只意味着您必须多次维护它
对我来说,重要的是(问题的编辑改变了这一点),用它执行手工构建的SQL字符串应该尽可能困难
例如,您可以使用自定义枚举替换任何字符串
参数(您最初使用了该参数,但后来用PreparedStatement
替换了该参数):
public enum SQLQuery {
QUERY1("SELECT foo FROM BAR", 0),
QUERY2("SELECT foo from BAR where baz = ?"; 1);
private final String sql;
private final int argumentCount;
private SQLQuery(final String sql, final int argumentCount) {
this.sql = sql;
this.argumentCount = argumentCount;
}
public String getSQL() {
return sql;
}
public int getArgumentCount() {
return argumentCount;
}
}
然后您可以这样编写您的方法:
public ResultSet executeQuery(SQLQuery query, Object... arguments) {
// implementation left as an exercise for the reader
}
通过这种方式,您可以非常确定您(或您团队中的任何其他人)不会意外地将自建字符串
传递到您的方法中
如有必要,这种方法可以扩展到处理不同的参数类型,但在许多情况下,使用setObject()
就可以了
为了增加模块性,您可以从该枚举中提取接口,并允许多个枚举定义查询(例如,如果您的项目中有单独的模块)。但这有一个缺点,即恶意(或无知)开发人员可以使用
SQLQuery
的动态非枚举实现将其手动构建的SQL字符串放入该方法。SQL注入漏洞取决于queryText
的生成方式。此外,您没有像应该的那样使用PreparedStatement
。您应该准备一次语句,然后向其提供参数。按照我在代码中看到的方式,您每次都在准备一个新的PreparedStatement
。此外,我认为没有必要在代码中嵌套try
块。对不起,我从未见过原始代码。我猜他们可能通过了事先准备好的声明。我们已经更新了代码来实现这一点,这样我们就可以把重点放在方法和内联问题上。这对您的代码来说是一个巨大的变化。现在的情况是,我没有看到SQL注入漏洞,因为您似乎使用了正确的方法PreparedStatement
。方法是声明为private
还是public
,这并不重要。实际上,此时SQL注入已经发生了,所以传入String
还是PreparedStatement
其实并不重要。如果您从手动构建的SQL字符串构建了PreparedStatement
,那么它同样糟糕。请看我对这个问题的第一个评论。我不认为使用原始sql字符串是一个值得关注的问题。@Foo:你的意思是“对单个类完成的所有查询执行查询会增加sql注入攻击的风险。”有何评论?据我所知,这是一个错误的陈述(除非有其他遗漏的问题)。是的,我的意思只是将执行放在私有方法中而不是内联。谢谢。这符合我的直觉,即不复制代码。还可以通过使用枚举来处理原始SQL字符串操作。还可以考虑一个“真实”的ORM系统,如Hibernate或另一个JPA实现,因为它们也可以很容易避免SQL注入漏洞(除了提供其他有用的特性)。将对象参数传递给executeQuery如何比在调用方方法中接受用户输入提供更多的针对恶意参数的保护?对象参数的值最终必须来自调用方,对吗?这样做的目的是避免将参数解释为SQL代码。这是通过以不同的方式处理它们来实现的(从已知良好的SQL代码构建PreparedStatement
,并使用set*()
设置可能有害的参数)。如果参数本身有效,则此机制不会检查。它只是确保它们不会以SQL代码的形式执行。另外:如果您将PreparedStatement
接受到此方法中,您将无法知道该语句是使用已知良好的SQL语句构造的,还是使用用户输入生成的SQL字符串构造的。