我手頭有個古老的項目束倍,持久層用的是古老的ADO.net。前兩天去昆明旅游儿礼,其中的一個景點是云南民族村,通過導游介紹知道了一個古老的民族——基諾族庆寺,“基”在這個族內代表舅舅蚊夫,“基諾”意為“跟在舅舅后邊”,加以引申即為“尊崇舅舅的民族”懦尝,很有意思吧知纷,這是我國最后一個被發(fā)現并確認下來的少數民族,即第56個民族陵霉。 項目里的ado.net和基諾族一樣古老琅轧。
尊崇舅舅的民族-基諾族
話說,項目里數據訪問層踊挠,數據操作sql絕大多數是通過字符串拼接的乍桂,這給sql注入提供了可乘之機,為了系統(tǒng)安全效床,決定在有限的時間內睹酌,將其改成參數化SQL。
其中剩檀,有個根據多個訂單號查詢支付單的方法憋沿,簽名如下:
public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)
那么,問題來了沪猴,因為sql里有in辐啄, 而 in(@no)的方式是行不通的。
怎么辦呢运嗜? 首先想到的是對參數做處理:
public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)
{
string sql = @"select * from T_AlipayNotityRecord where trade_status=@trade_status and trade_no in(@trade_no)";
//string inValue = "'" + string.Join("','", trade_no) + "'";//= string.Join(",", trade_no)
string inValue = "";
trade_no.ToList().ForEach(no => inValue += " union all select '" + no+"'");
inValue = inValue.Substring(" union all".Length);
List<SqlParameter> paramList = new List<SqlParameter>()
{
new SqlParameter("@trade_status",status.ToString()),
new SqlParameter("@trade_no",inValue),
};
var ds = SqlHelper.SqlDataSet(ConfigFile.PayCenterConnection, sql, CommandType.Text, paramList.ToArray());
if (ds == null || ds.Tables.Count == 0)
return null;
return ds.Tables[0];
}
經測試壶辜,無效。通過分析可知洗出,sqlhelper會把你參數值當成字符串士复,不會對其做轉義。所以,不管怎么對參數值處理阱洪,都還是一串字符串便贵。
按這樣的原理往下想,只能是將單號分開來傳遞給sql了冗荸。那么正好sql的in可以通過如下幾種方式等效實現:
sql里有臨時表承璃,可以in一個臨時表--這時,可以考慮and trade_no in(select @p1 union all select @p2 union all...)的方式
把sql的in集合蚌本,轉換為一個用or拼接起來的集合---即盔粹,and (trade_no=@p1 or trade_no=@p2 or trade_no=@p3 or...)
如下代碼是按照后者的思路解決了這個問題:
public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)
{
string sql = @"select * from T_AlipayNotityRecord where trade_status=@trade_status and ({0})";
List<SqlParameter> paramList = new List<SqlParameter>()
{
new SqlParameter("@trade_status",status.ToString()),
};
string partOfIN = "";
for (int i=0;i<trade_no.Length;i++)
{
partOfIN += " or trade_no=@no" + i;
paramList.Add(new SqlParameter("@no" + i, trade_no[i]));
}
sql = string.Format(sql, partOfIN.Substring(" or ".Length));
var ds = SqlHelper.SqlDataSet(ConfigFile.PayCenterConnection, sql, CommandType.Text, paramList.ToArray());
if (ds == null || ds.Tables.Count == 0)
return null;
return ds.Tables[0];
}