用C#构建动态查询(SQL注入攻击)

本文关键字:SQL 注入 攻击 查询 构建 动态 | 更新日期: 2023-09-27 18:24:29

我有以下代码

public DataSet GetProject(string projectID)
{
   DataSet dataTable = new DataSet(); 
   DataAccess dataAccess = new DataAccess();
   OracleCommand commandOb = new OracleCommand();
   strQuery.Append("select projectName, managerName");
   strQuery.Append("from project ");
   strQuery.Append("where projectID = '" + projectID + "'");
   cmd.CommandText = strQuery.ToString();
   dataTable = dataAccess.ExecuteDataAdapter(commandOb);
   return dataTable;
}

这是构建查询并执行查询的好方法吗?这会对SQL注入攻击造成漏洞吗?

当涉及到动态构建查询时,是否有推荐的方法。如有任何帮助,我们将不胜感激。

用C#构建动态查询(SQL注入攻击)

以这种方式构建查询确实会使其容易受到SQL注入攻击,除非您手动转义了输入(例如,使'projectID'的值无法通过使用数据库引擎特定的转义序列来更改查询的结构)。但是,建议使用参数化查询(有时称为"Prepared Statements")。使用参数化查询,只需定义查询的结构,然后将输入值单独作为参数提供,就可以防止通过SQL注入更改查询的结构。

以下是您的示例,更改为使用参数化:

public DataSet GetProject(string projectID)
{
   DataSet dataTable = new DataSet(); 
   DataAccess dataAccess = new DataAccess();
   OracleCommand commandOb = new OracleCommand();
   strQuery = @"select projectName, managerName
                  from project
                  where projectID = :ProjectID"
   cmd.CommandText = strQuery;
   cmd.Parameters.AddWithValue("ProjectID", projectID);
   dataTable = dataAccess.ExecuteDataAdapter(commandOb);
   return dataTable;
}

查询中的参数":ProjectID"将替换为"AddWithValue"方法中给定的值。无论"projectID"变量中有什么值,它都将始终作为WHERE子句的一部分进行计算。然而,以前,类似于[';DELETE FROM project;--]的值可能会通过将查询更改为以下内容而产生不良影响:

select projectName, managerName
  from project
  where projectID = ''; DELETE FROM project;--'

是的,查询易受sql注入的攻击。如果projectID是通过其他查询在应用程序中进行内部检索的,那么它就不那么容易受到攻击,因为没有直接的用户输入。

但是,如果某个用户输入是:"=1' OR 'a'=a'",那么将检索所有项目,允许在没有适当授权的情况下访问数据。更糟糕的是,可能会执行意外的命令,例如删除所有记录。

尽管如此,最佳实践是使用参数化查询或绑定参数,以获得更好的性能和针对注入的安全性。参数化查询转义保留字符,但仍然需要手动写出所有查询。替代方案包括使用ORM等。

请参阅https://www.owasp.org/有关sql注入的更多信息和有用的.net特定博客系列,以及更多信息:http://www.troyhunt.com/2010/05/owasp-top-10-for-net-developers-part-1.html

using (var cn = new OracleConnection(connString))
{
  var sql = "select projectName, managerName from project where projectID = :p1";
  using (var cmd = new OracleCommand(sql, cn))
  {
    cmd.BindByName = true; 
    cmd.Parameters.Add(new OracleParameter(":p1", OracleDbType.Varchar2, projectID,
                                            ParameterDirection.Input));
    using (var adapter = new OracleDataAdapter(cmd))
    {
      cn.Open();
      var dataSet = new DataSet();
      adapter.Fill(dataSet);
      return dataSet;
    }
  }
}

注意:这是odp.net