1

我很有趣在我的 ASP.net 应用程序中添加参数化 sql 查询。我看过一些关于避免 SQL 注入的好文章。

string sql = string.Format("INSERT INTO [UserData] (Username, Password, Role, Membership, DateOfReg) VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)");
        SqlCommand cmd = new SqlCommand(sql, conn);
        try
        {
        cmd.Parameters.AddWithValue("Username", usernameTB.Text);
        cmd.Parameters.AddWithValue("Password", passwordTB.Text);
        cmd.Parameters.AddWithValue("Role", roleTB.Text);
        cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
        cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);

        conn.Open();
        cmd.ExecuteNonQuery();
        conn.Close();

找到参考

但是这种方式对我没有用,因为我将数据库连接耦合到单独的类,因为我已经重用了它。

public class DBconnection{     
    public int insertQuery(String query) {



            int affectedRowCount = 0;
            SqlConnection conn = null;
            try{

                conn = new SqlConnection("Server=localhost;Database=master;UID=sa;PWD=sa;");
                SqlCommand cmd = new SqlCommand( query, conn );
                cmd.CommandType = CommandType.Text;

                conn.Open(  );
                affectedRowCount = cmd.ExecuteNonQuery(  );
                conn.Close(  );         

            } catch ( Exception e ){

                       String error = e.Message;

            }

            return affectedRowCount;
    }
}

因此我只使用下面的代码部分来调用上面的类并将值插入数据库。

 String SQLQuery1 = insert into Article values('" + Txtname.Text + "','" + TxtNo.Text + "','" + Txtdescription.Text + "' ,0)");
DBconnection dbConn = new DBconnection();
        SqlDataReader Dr = dbConn.insertQuery(SQLQuery1);

请帮助我使用 Parameterize sqlString 来避免我的 Sql 注入。要使用 @name 、 @No 和 @description 而不使用文本框输入。

4

3 回答 3

1

您编写特定的 InsertQuery 方法而不是通用的 InsertQuery() 方法怎么样?

例如:

public void AddNewUser(User u)
{
   var query = "insert Users (name, password) values (@0, @1)";
   SqlCommand cmd = new SqlCommand(query, conn);
        try
        {
        cmd.Parameters.AddWithValue("@0", u.UserName);
        cmd.Parameters.AddWithValue("@1", u.Password);
        }
}

这样做的好处是您的所有 SQL 逻辑都在这个其他类中,而不是调用类需要知道如何构造查询等。

它还使您的代码更具可读性,因为您将AddUseror视为方法调用UpdateUserChangePassword而不必在那一刻阅读 SQL 来尝试猜测程序中发生了什么。

但是,如果您要做这样的事情,您应该查看一些 MicroORM,我个人最喜欢的是PetaPoco(或NuGet 版本

PetaPoco 和 Massive 和 Dapper 等其他工具可以让您执行以下操作:

database.Insert(u);

其中 u 是映射到数据库表的用户对象。它使用 ADO.NET 并确保使用 SQL 参数。

于 2012-04-22T16:43:36.857 回答
1

这样做是完全合理的,但是让你的类回调(lambda/delegate)来获取参数。这是一个类中的静态方法,由各种重载的实例方法调用:

private static int SqlExec(string ConnectionString, string StoredProcName, Action<SqlCommand> AddParameters, Action<SqlCommand> PostExec)
        {
            int ret;
            using (var cn = new SqlConnection(ConnectionString))
            using (var cmd = new SqlCommand(StoredProcName, cn))
            {
                cn.Open();
                cmd.CommandType = CommandType.StoredProcedure;

                if (AddParameters != null)
                {
                    AddParameters(cmd);
                }

                ret = cmd.ExecuteNonQuery();

                if (PostExec != null)
                {
                    PostExec(cmd);
                }
            }
            return ret;
        }

然后,一个使用示例:

    public void Save()
    {
        Data.Connect().Exec("Project_Update", Cm =>
        {
            Cm.Parameters.AddWithValue("@ProjectID", ID);
            Cm.Parameters.AddWithValue("@PrimaryApplicantID", PrimaryApplicant.IdOrDBNull());
            Cm.Parameters.AddWithValue("@SecondaryApplicantID", SecondaryApplicant.IdOrDBNull());
            Cm.Parameters.AddWithValue("@ProjectName", ProjectName.ToDBValue());
        });
    }

也可以通过非存储过程调用来做到这一点。

在您的情况下,它看起来像:

DBconnection.InsertQuery(
    "INSERT INTO [UserData]
        (Username, Password, Role, Membership, DateOfReg)
        VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)"
    ,cmd => {
                cmd.Parameters.AddWithValue("Username", usernameTB.Text);
                cmd.Parameters.AddWithValue("Password", passwordTB.Text);
                cmd.Parameters.AddWithValue("Role", roleTB.Text);
                cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
                cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
            }
);

它可以按照您想要的方式将所有数据库内容放在一起,并让 DBconnection 保持其内部隔离。

于 2012-04-23T01:28:36.103 回答
0

我建议使用 LINQ to SQL,它会自动对所有内容进行参数化

问:如何保护 LINQ to SQL 免受 SQL 注入攻击?

A. SQL 注入对于通过连接用户输入形成的传统 SQL 查询来说是一个重大风险。LINQ to SQL 通过在查询中使用 SqlParameter 来避免这种注入。用户输入转化为参数值。这种方法可以防止使用来自客户输入的恶意命令。

您可以使用 a 以直接的方式插入、更新和删除DataContextSQL 数据库(右键单击您的项目以添加新项目并添加LINQ to SQL Classes模板,然后使用服务器资源管理器向其中添加对象)。

我有一段时间没有使用这个了,但我相信你的代码看起来有点像这样:

UserData user = new UserData();

user.Username = ...;
user.Password = ...;
user.Role = ...;
user.Membership = ...;
user.DateOfReg = ...;

db.UserDatas.InsertOnSubmit(user);
db.SubmitChanges();

当您调用 SubmitChanges 时,LINQ to SQL 会自动生成并执行将您的更改传输回数据库所必须的 SQL 命令。

编辑1:

作为补充说明,要从数据库中检索现有项目,您可以这样做:

var user = (from i in db.UserDatas
            where i.UserName == "devan"
            select i).Single();

哦,正如我在使用登录信息回答有关数据库的问题时的标准策略一样,我必须恳求您,看在上帝的爱和所有神圣的事物上,对您的用户密码进行加盐和哈希处理。

于 2012-04-22T16:47:51.283 回答