0

我曾经有人指出,使用私有方法来处理由单个类完成的所有查询的查询执行会增加 SQL 注入攻击的风险。

此方法的示例可能如下所示(如下)。我省略了一些细节,以免分散任何人的注意力。

如果您想谈论实施,请随时在评论中。安全审查没有评论方法的内容,但主要是它不应该是自己的方法。

请注意,queryText 是从一个受保护的静态最终字符串生成的,该字符串包含准备好的语句的 SQL 文本。准备好的语句文本中的 ? 是使用 PreparedStatement 的 setString(或设置其他)方法设置的。在准备好的语句上设置的变量以尽可能强的类型进入调用者方法。

然后将 queryText 传递给私有方法。

    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,因为我认为它符合特定的安全编程问题。

我想不出为什么将这段代码(从私有方法)复制到许多类中会增加任何保护。会吗?

谢谢

4

2 回答 2

1

如果此方法正在执行的查询具有 SQL 注入所需的成分,那么无论private/public方法如何,都会产生影响。

这个私有方法将被一些从用户(或)数据库获取输入的公共方法调用。如果该输入是恶意的,私有方法无法阻止它执行。

不要使用原始 SQL 字符串,最好使用准备好的语句。

于 2013-01-07T17:39:07.797 回答
1

有一个中央(不重复的)地方来执行查询是个主意。从代码可维护性和安全角度来看。为什么有可能多次出现问题的代码?这仅意味着您必须多次维护它!

对我来说似乎很重要(并且已通过对问题的编辑而改变)是用它来执行手工构建的 SQL 字符串应该尽可能困难。

例如,您可以使用自定义枚举替换任何String参数(您最初拥有,但后来替换为 a ):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
}

通过这种方式,您可以非常确定您(或团队中的任何其他人)不会意外地将自构建传递String到您的方法中。

如有必要,可以扩展此方法以处理不同的参数类型,但在许多情况下使用setObject()效果很好。

为了增加模块化,您可以从该枚举中提取一个接口并允许多个枚举来定义查询(例如,如果您的项目中有单独的模块)。但这有一个缺点,即恶意(或无能)开发人员可以使用动态非枚举实现SQLQuery将他们手动构建的 SQL 字符串放入该方法中。

于 2013-01-07T17:39:55.617 回答