我们以登录用户为例:
正常的查询应该是这样的
SELECT name, lastLogin
FROM [tblUsers]
where username = 'balexandre' AND password = 'veryhard';
当把它放到代码中时,它会很不错
using (SqlConnection connection = new SqlConnection(connectionString)) {
DataSet userDataset = new DataSet();
string query = "SELECT name, lastLogin FROM [tblUsers] where username = '" + txtUser.Text.Trim() + "' AND password = '" + txtPassword.Text.Trim() + "'";
SqlDataAdapter myCommand = new SqlDataAdapter(query, connection);
myCommand.Fill(userDataset);
}
但这不会阻止 SQL 注入,因为,尝试想象如果我在用户名文本框中添加类似 % 的内容,并在密码文本框中添加类似 ' OR 1=1-- 的内容,或者只是在用户名文本框中添加 ' OR 1=1-- 会发生什么。这将是有效的:1 实际上等于1,我将登录...
传递的查询会是这样的:
SELECT name, lastLogin
FROM [tblUsers]
where username = '' OR 1=1 --' AND password = '';
你明白了吧?
但如果我们在查询中使用参数,这将永远不会发生,如下所示:
using (SqlConnection connection = new SqlConnection(connectionString)) {
DataSet userDataset = new DataSet();
string query = "SELECT name, lastLogin FROM [tblUsers] where username = @username AND password = @password";
SqlDataAdapter myCommand = new SqlDataAdapter(query, connection);
myCommand.SelectCommand.Parameters.Add("@username", SqlDbType.VarChar, 30);
myCommand.SelectCommand.Parameters["@username"].Value = txtUser.Text.Trim();
myCommand.SelectCommand.Parameters.Add("@password", SqlDbType.VarChar, 30);
myCommand.SelectCommand.Parameters["@password"].Value = txtPassword.Text.Trim();
myCommand.Fill(userDataset);
}
如果你想使用 Store Procedures,也一样:
using (SqlConnection connection = new SqlConnection(connectionString)) {
DataSet userDataset = new DataSet();
string query = "spGetUser";
SqlDataAdapter myCommand = new SqlDataAdapter(query, connection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
myCommand.SelectCommand.Parameters.Add("@username", SqlDbType.VarChar, 30);
myCommand.SelectCommand.Parameters["@username"].Value = txtUser.Text.Trim();
myCommand.SelectCommand.Parameters.Add("@password", SqlDbType.VarChar, 30);
myCommand.SelectCommand.Parameters["@password"].Value = txtPassword.Text.Trim();
myCommand.Fill(userDataset);
}
现在,如果您工作并使用数据库 ORM(对象关系映射)之类的东西,您可以避免考虑所有这些,而不是纠正所有 SQL 的东西并担心这个,框架将为您处理所有已知操作。
最常用的数据库 ORM 之一是 NHibernate 和 ADO Entity Framework。
您可以对此使用 LINQ 查询,您的调用如下:
public User GetUser(string username, string password)
{
return _db.Users.FirstOrDefault(x => x.User == username && x.Password == password);
}
如果你有一个存储过程,也是一样的(下面的例子只是展示了另一种调用方式)
public User GetUser(string username, string password)
{
return (from u in _db.spGetUser(username, password)
select u).FirstOrDefault();
}
而且您无需考虑,缓存、注入、并发等...