编码平台:使用C#和ASP.NET作为后端的ASP.NET 2.0 WebForms
背景
我目前正在处理修复网站的错误 其中一个表“注册”有80列。
插入/更新是通过简单的sql语句完成的,没有任何参数化查询。
问题
在注册时,用户可以改变许多参数,从而导致至少15种INSERT查询。我的问题是如何确保插入所有字段的正确值。
所以,我创建了一个
Dictionary<string, string> fields = new Dictionary<string, string>();
fields.Add("LoginEmail", MySQL.SingleQuoteSQL(txtLoginEmail.Text));
fields.Add("Password", MySQL.SingleQuoteSQL(txtLoginPassword.Text));
fields.Add("ContactName", MySQL.SingleQuoteSQL(txtContactName.Text));
fields.Add("City", MySQL.SingleQuoteSQL(txtCity.Text));
我的想法是制作一个像这样的简单插入查询
INSERT INTO registrations("all keys as comma separated string") VALUES ("all keys as comma separated string")
我的问题是
而且,还有哪些更好的方法?
P.S:我正在维护代码并使实体类将列映射到属性并存储值不是一个选项。
答案 0 :(得分:11)
string list<T>(IEnumerable<T> enumerable)
{
List<T> list = new List<T>(enumerable);
return string.Join(",", list.ToArray());
}
//...
string sql= String.Format("INSERT INTO registrations({0}) VALUES({1})",
list(fields.Keys),
list(fields.Values));
答案 1 :(得分:2)
我认为字典结构在这种情况下可以,但是
构建和执行字符串,允许SQL注入atacks
xkcd.com/327/对妈妈的剥削
我使用的是.NET 3.5,但这个想法也适用于.NET 2.0
如果MySQL.SingleQuoteSQL的功能超出了它的名称,那么请告诉我
否则将值添加为参数以防止此
var values = new Dictionary<string, string>() {
{"LoginEmail", "LoginEmail"},
{"Password", "Password"},
{"ContactName", "ContactName"},
{"City", "City"}
};
System.Func<string, string> key = p => String.Concat("?", p);
var statement = string.Format("INSERT INTO registrations ({0}) VALUES ({1})",
string.Join(",", values.Values.ToArray()),
string.Join(",", values.Keys.Select(key).ToArray())
);
//"INSERT INTO registrations (LoginEmail,Password,ContactName,City) VALUES (?LoginEmail,?Password,?ContactName,?City)"
foreach(var p in values) {
command.Parameters.Add(key(p.Key), p.Value, SqlDbType.Text);
}
command.Prepare();
command.ExecuteNonQuery();
They may be other better classes for .NET mysql, apologies if so - I haven't used mysql in .NET
答案 2 :(得分:1)
我知道描述说你没有使用参数化的sql,但是恕我直言,使用参数化的sql是一种更好的方法来防止sql注入。将一些SQL抛入txtLoginEmail并提交表格会对您的情况造成严重破坏并不需要花费太多精力。
private static string CreateInsertSql(string table, IDictionary<string, string> parameterMap) { var keys = parameterMap.Keys.ToList(); // ToList() LINQ extension method used because order is NOT // guaranteed with every implementation of IDictionary<TKey, TValue> var sql = new StringBuilder("INSERT INTO ").Append(table).Append("("); for (var i = 0; i < keys.Count; i++) { sql.Append(keys[i]); if (i < keys.Count - 1) sql.Append(", "); } sql.Append(") VALUES("); for (var i = 0; i < keys.Count; i++) { sql.Append('?').Append(keys[i]); if (i < keys.Count - 1) sql.Append(", "); } return sql.Append(")").ToString(); }
private static void SqlInsert(string table, IDictionary<string, string> parameterMap) { using (var connection = AcquireConnection()) { connection.Open(); using (var command = connection.CreateCommand()) { command.Connection = connection; command.CommandText = CreateInsertSql(table, parameterMap); foreach (var pair in parameterMap) command.Parameters.Add(pair.Key, pair.Value); command.ExecuteNonQuery(); } } }
调用类似于:
SqlInsert("registrations", new Dictionary<string, string>() { { "LoginEmail", txtLoginEmail.Text }, { "Password", txtLoginPassword.Text }, { "ContactName", txtContactName.Text }, { City", txtCity.Text } });