【问题标题】:Creating safe SQL statements as strings将安全的 SQL 语句创建为字符串
【发布时间】:2010-09-22 12:53:23
【问题描述】:

我正在使用 C# 和 .NET 3.5。我需要生成并存储一些 T-SQL 插入语句,这些语句稍后将在远程服务器上执行。

例如,我有一个员工数组:

new Employee[]
{
   new Employee { ID = 5, Name = "Frank Grimes" },
   new Employee { ID = 6, Name = "Tim O'Reilly" }
}

我需要得到一个字符串数组,像这样:

"INSERT INTO Employees (id, name) VALUES (5, 'Frank Grimes')",
"INSERT INTO Employees (id, name) VALUES (6, 'Tim O''Reilly')"

我正在查看一些使用 String.Format 创建插入语句的代码,但这感觉不对。我考虑过使用 SqlCommand(希望做something like this),但它没有提供将命令文本与参数结合起来的方法。

仅仅替换单引号并构建一个字符串就足够了吗?

string.Format("INSERT INTO Employees (id, name) VALUES ({0}, '{1}')",
    employee.ID,
    replaceQuotes(employee.Name)
    );

这样做时我应该注意什么?源数据是相当安全的,但我不想做太多假设。

编辑:只想指出,在这种情况下,我没有 SqlConnection 或任何直接连接到 SQL Server 的方法。这个特定的应用程序需要生成 sql 语句并将它们排队以在其他地方执行 - 否则我将使用 SqlCommand.Parameters.AddWithValue()

【问题讨论】:

  • AddWithValue 很棒(我经常使用它),但是如果不小心使用它可能会遭受错误的隐式类型转换。

标签: c# .net sql concatenation stringbuilder


【解决方案1】:

像这样创建你的 SqlCommand 对象:

SqlCommand cmd = new SqlCommand(
        "INSERT INTO Employees (id, name) VALUES (@id, @name)", conn);

SqlParameter param  = new SqlParameter();
param.ParameterName = "@id";
param.Value         = employee.ID;

cmd.Parameters.Add(param);

param  = new SqlParameter();
param.ParameterName = "@name";
param.Value         = employee.Name;

cmd.Parameters.Add(param);

cmd.ExecuteNonQuery();

【讨论】:

  • 使用“cmd.AddWithValue("@id", employee.ID);"更简洁。
  • 我经常得到这个,并且在我对这个问题的回答中也得到了这个。
  • Brad Wilson:需要一个额外的“.Parameters”:cmd.Parameters.AddWithValue("@id", employee.ID);
  • 这如何回答这个问题? OP 明确声明他们无权访问数据库,而是需要输出可以在以后运行的命令。
【解决方案2】:

使用参数化命令。将参数也传递给您的远程服务器,并让它调用 SQL Server,仍然保持 SQL 本身和参数值之间的区别。

只要你从不将数据视为代码,就应该没问题。

【讨论】:

  • 其实现在就去睡觉了。明天早上 10.30-11.30 布道,所以你一定会在鞭子上打得很好! ;)
  • 讲道?有录音吗?
  • @tofutim:我不知道。
  • 当硬要求输出是 .sql 脚本文件和现成的 INSERT 命令以及要插入的数据时,这似乎不能提供解决方案。
  • @O.R.Mapper:确实 - 请注意,OP 在我回答后添加了该要求,尽管他们仍然接受了我的回答,但很奇怪......
【解决方案3】:

以这种方式修复替换引号功能:

void string replaceQuotes(string value) {
     string tmp = value;
     tmp = tmp.Replace("'", "''");
     return tmp;
}

干杯!

【讨论】:

  • 使用参数要容易得多,想想所有必须转义的字符。而且这也不是 SQL 注入安全的。
  • @KarelFrajták:如问题中所述,当格式化命令仅在稍后执行(大概是在 C# 代码执行完成后)时,如何使用参数?
  • @O.R.Mapper,在这种情况下,我会将语句和带有参数名称和值的字典排队。
【解决方案4】:

嗯,我同意其他所有人的观点,即您应该使用参数化查询并将其保留。但是你如何将这些 sql 语句传递给你的远程服务器呢?您是否有某种类型的服务,例如接受并执行任意 Sql 命令的 Web 服务,还是您的客户端应用程序会直接访问数据库?

如果您通过某种代理,那么无论您如何清理客户端上的数据,黑客都可能绕过您的应用并攻击该服务。在这种情况下,请按照 Cade 的建议执行并将数据作为 XML 或您选择的任何格式(JSON、二进制等)传递。然后在您实际运行命令之前构建您的 SQL。

【讨论】:

    【解决方案5】:

    为避免注入,您需要将数据传送到远程服务器(可能是 XML),然后在远程服务器上,数据应转换回适当的数据类型并用于参数化查询或存储过程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-23
      • 1970-01-01
      • 2010-12-06
      • 2017-01-17
      • 2020-10-07
      • 1970-01-01
      相关资源
      最近更新 更多