جواب كوتاه: بسيار زياد!
توضيحات:
string query = @"SELECT * FROM USER_PROFILE
WHERE LOGIN_ID = '"+loginId+@"' AND PASSWORD = '"+password+@"'";
protected void btnSearch_Click(object sender, EventArgs e)
{
String cmd = @"SELECT [CustomerID], [CompanyName], [ContactName]
FROM [Customers] WHERE CompanyName ='" + txtCompanyName.Text
+ @"'";
SqlDataSource1.SelectCommand = cmd;
GridView1.Visible = true;
}
راه حلي كه براي مقابله با آن در دات نت ارائه شده نوشتن كوئريهاي پارامتري است و در اين حالت كار encoding اطلاعات ورودي به صورت خودكار توسط فريم ورك مورد استفاده انجام خواهد شد؛ همچنين براي مثال اس كيوال سرور، execution plan اين نوع كوئريهاي پارامتري را همانند رويههاي ذخيره شده، كش كرده و در دفعات آتي فراخواني آنها به شدت سريعتر عمل خواهد كرد. براي مثال:
SqlCommand cmd = new SqlCommand("SELECT UserID FROM Users WHERE UserName=@UserName AND Password=@Password");
cmd.Parameters.Add(new SqlParameter("@UserName", System.Data.SqlDbType.NVarChar, 255, UserName));
cmd.Parameters.Add(new SqlParameter("@Password", System.Data.SqlDbType.NVarChar, 255, Password));
dr = cmd.ExecuteReader();
if (dr.Read()) userId = dr.GetInt32(dr.GetOrdinal("UserID"));
اما در مورد LINQ to SQL چطور؟
اين سيستم به صورت پيش فرض طوري طراحي شده است كه تمام كوئريهاي SQL نهايي حاصل از كوئريهاي LINQ نوشته شده توسط آن، پارامتري هستند. به عبارت ديگر اين سيستم به صورت پيش فرض براي افرادي كه داراي حداقل اطلاعات امنيتي هستند به شدت امنيت بالايي را به همراه خواهد آورد.
براي مثال كوئري LINQ زير را در نظر بگيريد:
var products = from p in db.products
where p.description.StartsWith(_txtSearch.Text)
select new
{
p.description,
p.price,
p.stock
};
exec sp_executesql N'SELECT [t0].[description], [t0].[price], [t0].[stock]
FROM [dbo].[products] AS [t0]
WHERE [t0].[description] LIKE @p0',N'@p0 varchar(5)',@p0='sony%'
db.Log = Console.Out;
همانطور كه ملاحظه ميكنيد، كوئري نهايي توليد شده پارامتري است و در صورت ورود اطلاعات خطرناك در پارامتر p0 ، هيچ اتفاق خاصي نخواهد افتاد و صرفا ركوردي بازگشت داده نميشود.
و يا همان مثال كلاسيك اعتبار سنجي كاربر را در نظر بگيريد:
public bool Validate(string loginId, string password)
{
DataClassesDataContext db = new DataClassesDataContext();
var validUsers = from user in db.USER_PROFILEs
where user.LOGIN_ID == loginId
&& user.PASSWORD == password
select user;
if (validUsers.Count() > 0) return true;
else return false;
}
SELECT [t0].[LOGIN_ID], [t0].[PASSWORD]
FROM [dbo].[USER_PROFILE] AS [t0]
WHERE ([t0].[LOGIN_ID] = @p0) AND ([t0].[PASSWORD] = @p1)
تذكر مهم هنگام استفاده از سيستم LINQ to SQL :
اگر با استفاده از LINQ to SQL مجددا به روش قديمي اجراي مستقيم كوئريهاي SQL خود همانند مثال زير روي بياوريد (اين امكان نيز وجود دارد)، نتيجه اين نوع كوئريهاي حاصل از جمع زدن رشتهها، پارامتري "نبوده" و مستعد به تزريق اس كيوال هستند:
string sql = "select * from Trade where DealMember='" + this.txtParams.Text + "'";
var trades = driveHax.ExecuteQuery<Trade>(sql);
اما روش صحيحي نيز در مورد بكارگيري متد ExecuteQuery وجود دارد. استفاده از اين متد به شكل زير مشكل را حل خواهد كرد:
IEnumerable<Customer> results = db.ExecuteQuery<Customer>(
"SELECT contactname FROM customers WHERE city = {0}", "Tehran");