我有一个我需要创建的应用程序,在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中没有给出数据类型,因此应用程序也必须确定。
答案 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这是正确的
这是不可能的,而且是矛盾的,你不能将String
与SqlParameters
一起使用。所以如果你以后再运行这些插件,我担心你会对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]) + ");";
如果有人可以加强这个让我知道!