关于代码中的存储过程和sql命令的问题

时间:2011-06-06 06:21:57

标签: asp.net sql stored-procedures

我是sql的新手,我尝试使用内联/内嵌代码sql命令对数据进行操作。但是,我知道你需要在trans-sql中编写很多代码。当我写它时,人们说它受到sql注入。然后我不知道该怎么做......

考虑到我不是数据库编程方面的专家,我会更容易做些什么。我应该使用存储过程还是内联文本。我如何将参数传递给存储过程? (例如,如果我有来自文本框的输入)。

3 个答案:

答案 0 :(得分:1)

我们举一个例子来登录用户:

正常查询类似于

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--或{{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); 
}

现在,如果你工作并使用像数据库ORM(对象关系映射)这样的东西,你可以避免考虑所有这些,而不是纠正所有SQL的东西而担心这个,框架将为您处理所有已知的操作。

最常用的数据库ORM之一是NHibernateADO Entity Framework

你可以使用LINQ查询,你的调用就像:

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); 
}

如果你有一个商店程序,它是一样的(下面的例子只显示另一种方式来调用它)

public User GetUser(string username, string password)
{
    return _db.Users.FirstOrDefault(x => x.User == username && x.Password == password);
}

您无需考虑,缓存注入并发等...

答案 1 :(得分:0)

您不必使用存储过程来避免'SQL注入;你只需要使用参数化查询(显然存储过程就是这样)。

The C# Station ADO.NET Tutorial

Using Parameters with a SqlCommand and a Stored Procedure

Bare bones示例(尚未编译):

string connectionString = "Server=(local);DataBase=Northwind;Integrated Security=SSPI";

using (SqlConnection conn = new SqlConnection(connectionString))
{
     conn.Open(); 
     SqlCommand cmd  = new SqlCommand("MyStoredProcName_CustOrderHist", conn);
     cmd.CommandType = CommandType.StoredProcedure;

     cmd.Parameters.Add(new SqlParameter("@CustomerID", custId));

     // execute the command
     SqlDataReader rdr = cmd.ExecuteReader();

     while (rdr.Read())
     {
          // do something with results
     }


     conn.close;
}

答案 2 :(得分:0)

存储过程不是编写sql注入安全代码的强制选项。您可以使用可以解决SQL注入攻击的参数化查询。