简体   繁体   English

私有查询方法会增加SQL注入攻击风险吗?

[英]Does a private query method increase SQL injection attack risk?

I've had someone point out that using a private method to handle query execution for all queries done by a single class increases the risk of SQL injection attacks. 我曾经有人指出,使用私有方法处理由单个类完成的所有查询的查询执行会增加SQL注入攻击的风险。

An example of this method might look like this (below). 此方法的示例可能如下所示(如下所示)。 I have omitted some specifics so as not to distract anyone on implementation. 我省略了一些细节,以免分散任何人的注意力。

If you want to talk implementation, please feel free to in the comments. 如果您想谈谈实施,请随时在评论中。 The security review did not comment on the contents of the method, but mainly the fact that it should not be its own method. 安全审查没有评论该方法的内容,但主要是它不应该是自己的方法。

Note, queryText is generated from a protected static final string containing SQL text for a prepared statement. 注意,queryText是从包含预准备语句的SQL文本的受保护静态最终字符串生成的。 The ?'s in the prepared statement text are set using PreparedStatement's setString (or set whatever) method. 准备好的语句文本中的?是使用PreparedStatement的setString(或set whatever)方法设置的。 The variables that are set on the prepared statement come into the caller method as strongly typed as possible. 在预准备语句中设置的变量尽可能强类型地进入调用方法。

queryText is then passed to the private method. 然后将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
}

The recommended alternative was to basically inline the same code in each method that does a query. 推荐的替代方法是在执行查询的每个方法中基本内联相同的代码。

I did not post this to security.stackexchange.com because I believe it qualifies as a specific security programming problem. 我没有将此发布到security.stackexchange.com,因为我认为它有资格作为特定的安全编程问题。

I can think of no reason why duplicating this code (from a private method) into many classes would add any protection. 我认为没有理由为什么将这个代码(从私有方法)复制到许多类中会增加任何保护。 Would it? 是吗?

Thank you 谢谢

If the query being executed by this method has ingredients required for SQL Injection, then irrespective of private/public method, it will impact. 如果此方法执行的查询具有SQL注入所需的成分,那么无论private/public方法如何,它都会产生影响。

This private method will be invoked by some public method which takes input from either user (or) database. 这个私有方法将由一些公共方法调用,该方法从用户(或)数据库获取输入。 If that input is malicious, private method can't stop it from executing. 如果该输入是恶意的,则私有方法无法阻止它执行。

Don't use raw SQL strings, always better to use prepared statements. 不要使用原始SQL字符串,总是更好地使用预准备语句。

Having a central (un-duplicated) place for executing queries is a good idea. 拥有一个执行查询的中心(不重复)位置是个主意。 Both from a code-maintainability and from a security standpoint. 从代码可维护性和安全性角度来看都是如此。 Why have code that could have problems multiple times? 为什么代码可能多次出现问题? It only means that you'll have to maintain it multiple times! 这只意味着你必须多次维护它!

What seems important to me (and which has changed by an edit of the question) is that it should be as hard as possible to execute hand-built SQL Strings with it. 对我来说似乎很重要(以及通过编辑问题而改变的)是,应该尽可能地用它来执行手工构建的SQL字符串。

You could, for example, replace any String parameters (which you had initially, but since then replace with a PreparedStatement ) with a custom enum: 例如,您可以使用自定义枚举替换任何String参数(您最初使用,但从那时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;
  }
}

Then you can write your method like this: 然后你可以像这样编写你的方法:

public ResultSet executeQuery(SQLQuery query, Object... arguments) {
  // implementation left as an exercise for the reader
}

This way you can be pretty sure that you (or anyone else on your team) don't accidentally passes in a self-build String into your method. 通过这种方式,您可以非常确定您(或团队中的任何其他人)不会意外地将自构建String传递给您的方法。

If necessary this approach could be extended to handle different parameter types but for many cases using setObject() works just fine. 如果有必要,可以扩展此方法以处理不同的参数类型,但对于许多情况,使用setObject()工作正常。

For increased modularity you could extract an interface from that enum and allow multiple enums to define queries (for example if you have separate modules in your project). 为了提高模块性,您可以从该枚举中提取接口,并允许多个枚举定义查询(例如,如果项目中有单独的模块)。 But this has the drawback that malicious (or clueless) developers could use dynamic non-enum implementations of SQLQuery to get their manually-built SQL strings into that method. 但这有一个缺点,即恶意(或无能)的开发人员可以使用SQLQuery动态非枚举实现来将他们手动构建的SQL字符串放入该方法中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM