SqlCommand以参数作为字符串

时间:2012-04-25 10:39:07

标签: c# sql sql-injection sqlcommand sqlparameters

我有一个我需要创建的应用程序,在CSV格式的用户输入中,需要解析并生成多种格式的CSV。其中一种格式是每行CSV的一系列SQL INSERT语句(作为字符串)。

(此时您可以假设我已经将CSV解析为值列表或其他内容,因此这不是问题的重点)

鉴于此输入可能包含漏洞,我希望生成已经过验证和清理的INSERT语句。

我熟悉创建一个SqlCommand对象并在其参数列表中添加值,但查看a similar question它似乎并不像我希望的那样工作。

那么有没有办法像我需要的那样以字符串形式生成已清理的SQL语句?

编辑:这是我想要做的一个例子。

CSV:

id,name,country
1,Alice,France
2,Bob,Austria
3,Carol,Germany

SQL:

...
INSERT INTO Users (id, name, country) VALUES (1, 'Alice', 'France');
INSERT INTO Users (id, name, country) VALUES (2, 'Bob', 'Austria');
INSERT INTO Users (id, name, country) VALUES (3, 'Carol', 'Germany');
...

由于CSV中没有给出数据类型,因此应用程序也必须确定。

3 个答案:

答案 0 :(得分:1)

因为我不知道您是如何存储变量的,所以我会使用List<Dictionary<String, Object>>()向您展示一个完整的,可能的实例数据:

添加样本数据:

var tableName = "Users";
var records = new List<Dictionary<String, Object>>();
var recordFields = new Dictionary<String, Object>();
recordFields.Add("id", 1);
recordFields.Add("name", "Alice");
recordFields.Add("country", "France");
records.Add(recordFields);
recordFields = new Dictionary<String, Object>();
recordFields.Add("id", 2);
recordFields.Add("name", "Bob");
recordFields.Add("country", "Austria");
records.Add(recordFields);
recordFields = new Dictionary<String, Object>();
recordFields.Add("id", 3);
recordFields.Add("name", "Carol");
recordFields.Add("country", "Germany");
records.Add(recordFields);

生成参数化插入语句:

using (var con = new SqlConnection(Settings.Default.ConnectionString))
{
    con.Open();
    foreach (var record in records)
    {
        String insertSql = String.Format("INSERT INTO {0} ({1}) VALUES ({2});"
            , tableName
            , String.Join(",", record.Select(r => r.Key))
            , String.Join(",", record.Select(r => "@" + r.Key)));
        using (var insertCommand = new SqlCommand(insertSql, con))
        {
            foreach (var field in record)
            {
                var param = new SqlParameter("@" + field.Key, field.Value);
                insertCommand.Parameters.Add(param);
            }
            insertCommand.ExecuteNonQuery();
        }
    }
}

请注意,这并没有真正经过测试(它编译并且看起来不错),但无论如何它都会对你有所帮助。

修改

   @Oded:我认为问题是丹尼尔不想跑   插入,但显示/输出/保存它们。所以使用SqlCommand参数   没有好处,因为你没有看到生成的SQL。

     

@Cylindric这是正确的

这是不可能的,而且是矛盾的,你不能将StringSqlParameters一起使用。所以如果你以后再运行这些插件,我担心你会对Sql-Injection开放。当你实际运行statemenets时,我建议使用上面的代码。

答案 1 :(得分:1)

作为警示,并非如此答案。如果您最终需要采用“经典”转义路径来实现此目的,并且确实需要安全性(即数据来自不受信任的来源),请不要忘记它不仅仅是简单的逃避,您需要担心。

我们一直听到的基本角色逃脱:

  • ' -> ''撇号和东西非常明显并记录在案 ad-nauseum
  • ;一个语句中的多个命令 - 数据库并不总是允许,但危险

如果你正在解析“邪恶的行为”,你有没有想过:

  • SELECT/*not important*/1/*really...*/FROM/*im serious*/users
  • SELECT%09FIELDS%09FROM%0dTABLE_NAME
  • WHERE username=CONCAT(CHAR(97),CHAR(100),CHAR(109),CHAR(105),CHAR(110))
  • SELECT passwd FROM users WHERE username=0x61646d696e

总结:这里是龙。

http://www.ihteam.net/papers/blind-sqli-regexp-attack.pdf

http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/#HexbasedSamples

答案 2 :(得分:1)

如果您不想使用SQL对象,那么您可能需要自己对条目进行整理。我不知道SQL的任何推荐格式,但对于MySQL,以下方法可行。我已将其更改为使用SQL,但我不能保证它已涵盖所有可能的注入攻击。

public string sqlEscape(string VAL)
{
    if (VAL == null)
    {
        return null;
    }
    return "\"" + Regex.Replace(VAL, @"[\r\n\x00\x1a\\'""]", @"\$0") + "\"";
}

然后使用(假设您的CSV行存储在名为csv的数组中):

string query = @"INSERT INTO Users (id, name, country) VALUES (" + sqlEscape(csv[0]) + ", " + sqlEscape(csv[1]) + ", " + sqlEscape(csv[2]) + ");";

如果有人可以加强这个让我知道!