c# - SQL注入(inject)参数化查询

标签 c# sql database sql-injection

<分区>

我需要实现下面的功能

     public PartyDetails GetAllPartyDetails(string name)
    {
        try
        {
            String query = "select * from [Party Details] where name=@name ";
            pd = new PartyDetails();
            com = new SqlCeCommand(query, con);
            com.Parameters.AddWithValue("@name", name);
            con.Open();
            sdr = com.ExecuteReader();
            while (sdr.Read())
            {

                pd.name = sdr.GetString(0);

            }
            con.Close();
            return pd;
        }

        catch (Exception e)
        {
            con.Close();
            throw e;
        }
    }

但是这个函数对我来说效率不高,因为我不需要仅仅因为查询的变化而编写不同的函数代码。

现在这是我需要的

  public PartyDetails GetAllPartyDetails(string query)
        {
            try
            {
            pd = new PartyDetails();
            com = new SqlCeCommand(query, con);
            con.Open();
            sdr = com.ExecuteReader();
            while (sdr.Read())
            {
                pd.name = sdr.GetString(0);
            }
            con.Close();
            return pd;
        }
        catch (Exception e)
        {
            con.Close();
            throw e;
        }
    }

但它增加了 sql 注入(inject)的风险,因为它没有使用 com.Parameters.AddWithValue("@name", name);。是否有任何替代方法可以通过调用来实现停止sql注入(inject)的功能。

对于那些不明白我的问题的人

例如我有另一个查询 select * from [party details] where address=@address and name=@anme ,为此我需要再次编写一个我使用 的函数com.Parameters.AddWithValue("@address", 地址); com.Parameters.AddWithValue("@name", name);,这简直是在浪费时间。查询可以有不同的参数数量,我需要不依赖于查询参数数量的函数。

最佳答案

名为“GetAllPartyDetails”的函数应该接受一个 sql 字符串作为参数。像这样的方法的目的是抽象出应用程序的其余部分了解或关心 sql 的需要,并简单地提供与数据库实现分开的各方详细信息的来源。它应该接受派对名称作为参数,但如果您需要接受 sql 查询,那么您在错误的地方构建了 sql。

您需要的是一种方法,该方法不仅可以从 GetPartyDetails() 中调用,而且可以从需要来自特定数据源的数据的其他方法中调用。如果您在 GetPartyDetails 之外构建查询字符串,则需要稍微重新设计一下。

检索任何数据的方法应该是什么样的?当然它需要接受一个sql字符串。它还需要一些方法来接受参数信息。这可以像键/值对数组一样简单,但我更喜欢避免两次构建参数集合的代码。此参数也应该是必需的,而不是可选的或重载的,以鼓励良好的参数使用。

我目前使用这种模式,而且我非常喜欢它:

private IEnumerable<T> GetData(string sql, Action<SqlParameterCollection> addParams, Func<IDataRecord, T> translate)
{
    using (var cn = new SqlConnection("connection string here"))
    using (var cmd = new SqlCommand(sql, cn))
    {
       addParams(cmd.Parameters);
       cn.Open();
       using (var rdr = cmd.ExecuteReader())
       {
          while (rdr.Read())
          {
              yield return translate(rdr);
          }
       }
    }
}

这满足了我们通用数据访问方法的所有目标。唯一让我不满意的部分是翻译委托(delegate)的需要,这并不是什么大损失,因为这是您无论如何都必须在应用程序的某个级别编写的代码。如果您不将每一行复制到该方法内的新对象,您可能会得到意想不到的结果,因此我们需要一种方法将数据记录直接转换为业务对象。

你可以这样调用它:

public string GetPartyDetailsByName(string name)
{
    return GetData("select * from [Party Details] where name=@name", p =>
    {
       p.Add("@name", SqlDbType.NVarChar, 50).Value = name;
    }, row =>
    {
       row.GetString(0);
    }).First();
}

如果您有另一个带参数的查询,您可以这样调用它:

public string GetPartyDetailsByNameAddress(string name, string address)
{
    return GetData("select * from [Party Details] where name=@name and address=@address", p =>
    {
       p.Add("@name", SqlDbType.NVarChar, 50).Value = name;
       p.Add("@address", SqlDbType.NVarChar,200).Value = address;
    }, row =>
    {
       row.GetString(0);
    }).First();
}

不接受任何参数的方法如下所示:

public IEnumerable<string> GetAllPartyDetails()
{
    return GetData("select * from [Party Details]", p => {}, row =>
    {
       row.GetString(0);
    });
}

有点尴尬,但这就是重点。您希望人们慎重不使用参数,这样他们就会情不自禁地以正确的方式使用参数。

我知道您想避免编写两种方法,但这是处理数据访问的正确方式。是的,有一种方法可以与数据库对话,以帮助抽象出一些样板代码。但是为每个 sql 查询添加一个方法仍然是正确的做法。

您不需要完全遵循我的 GetData() 方法:函数式风格对某些人来说有点过分。但是您确实需要一个单一的方法,它是唯一可以向您的数据库发送查询的地方,并且该方法必须具有某种接受参数数据的机制。其他方法应该 传递 sql。这会导致注入(inject)问题。

您询问数据的每个问题都属于它自己的方法。理想情况下,这些方法聚集在一个类中,或者一组类聚集在一个项目中以用于更大的应用程序。

关于c# - SQL注入(inject)参数化查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16466300/

相关文章:

python - 使用 Python 将列表插入我的数据库

database - 通用开源分类数据库

mysql - 为什么 MySQL Workbench 会为 View 生成占位符表?

java - 如何用单独的枚举类填充JavaFX ChoiceBox?

c# - 如何在 ASP.NET Core 中保持对象存活?

c# - 不使用 Base 关键字访问静态变量隐藏的实例变量

c# - 自动实现属性的代码契约(Contract)

SQL...如何使用同一表中其他行的数据更新行?

javascript - 从隐藏的代码中过滤 TextBox 的 KeyPress 事件上的 GridView

sql - 通过使用 VIEW 而不是 JOIN,我可以获得任何性能优势吗?