简体   繁体   English

参数化查询与 SQL 注入

[英]parameterized queries vs. SQL injection

I am new to Asp.net and I'm just starting to work with classes.我是 Asp.net 的新手,我刚刚开始学习课程。 I recently created a class that will handle most of my SQL queries for me so that I don't have to repeatedly create new connections over all my files.我最近创建了一个类,它将为我处理大部分 SQL 查询,这样我就不必在所有文件上重复创建新连接。

One of the methods I've created takes in an SQL query as a parameter and returns the result.我创建的方法之一将 SQL 查询作为参数并返回结果。 I know that I should be using parameterized queries to avoid SQL injections.我知道我应该使用参数化查询来避免 SQL 注入。 My question is, how can I do this when I'm passing the query as a string parameter?我的问题是,当我将查询作为字符串参数传递时,我该怎么做?

For example, here's a method I'll be calling:例如,这是我将调用的方法:

public static DataTable SqlDataTable(string sql)
{
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
    {
        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.Connection.Open();
        DataTable TempTable = new DataTable();
        TempTable.Load(cmd.ExecuteReader());
        return TempTable;
    }
}

So from another file I'd like to use this method like so:所以从另一个文件我想像这样使用这个方法:

DataTable dt = new DataTable();

dt = SqlComm.SqlDataTable("SELECT * FROM Users WHERE UserName='" + login.Text  + "' and Password='" + password.Text + "'");

if (dt.Rows.Count > 0)
{
   // do something if the query returns rows
}

This works but would still be vulnerable to injections right?这有效,但仍然容易受到注射的影响,对吗? Is there a way I can pass the variables to the string as parameters?有没有办法可以将变量作为参数传递给字符串? I know I can do this if I create a new SQLCommand object for the query and use Parameters.AddWithValue, but I wanted all my SQL commands to be in the separate class.我知道如果我为查询创建一个新的 SQLCommand 对象并使用 Parameters.AddWithValue,我可以做到这一点,但我希望我的所有 SQL 命令都在单独的类中。

This works but would still be vulnerable to injections right?这有效,但仍然容易受到注射的影响,对吗?

Yeah, your code is terrifyingly vulnerable to SQL injections.是的,您的代码非常容易受到 SQL 注入的攻击。

I know that I should be using parameterized queries to avoid SQL injections.我知道我应该使用参数化查询来避免 SQL 注入。

Oh absolutely yeah.哦绝对是的。

My question is, how can I do this when I'm passing the query as a string parameter?我的问题是,当我将查询作为字符串参数传递时,我该怎么做?

You simply shouldn't be passing the query as a string parameter.您根本不应该将查询作为字符串参数传递。 Instead you should be passing the query as string parameter containing placeholders and the values for those placeholders:相反,您应该将查询作为包含占位符和这些占位符的值的字符串参数传递:

public static DataTable SqlDataTable(string sql, IDictionary<string, object> values)
{
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
    using (SqlCommand cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = sql;
        foreach (KeyValuePair<string, object> item in values)
        {
            cmd.Parameters.AddWithValue("@" + item.Key, item.Value);
        }

        DataTable table = new DataTable();
        using (var reader = cmd.ExecuteReader())
        {
            table.Load(reader);
            return table;
        }
    }
}

and then use your function like this:然后像这样使用你的函数:

DataTable dt = SqlComm.SqlDataTable(
    "SELECT * FROM Users WHERE UserName = @UserName AND Password = @Password",
    new Dictionary<string, object>
    {
        { "UserName", login.Text },
        { "Password", password.Text },
    }
);

if (dt.Rows.Count > 0)
{
   // do something if the query returns rows
}

What you're trying to do makes perfect logical sense and I can understand why you would arrive at this implementation.您正在尝试做的事情具有完美的逻辑意义,我可以理解您为什么要实现此实现。 However, what you're attempting to do is very dangerous and, being new to ASP.NET, you may not be aware that there are a variety of other options available to you that make managing your data much easier and much more secure.但是,您尝试执行的操作非常危险,而且作为 ASP.NET 的新手,您可能不知道还有多种其他选项可供您使用,这些选项可以让您更轻松、更安全地管理数据。

@iamkrillin hinted at one such technology -- Object Relational Mapping (ORM). @iamkrillin 暗示了一种这样的技术——对象关系映射(ORM)。 The .NET framework actually has first class support for an ORM called the Entity Framework . .NET 框架实际上对称为实体框架的 ORM 具有一流的支持。 I believe the reason he suggested that you look into an ORM is because your design is actually very similar in principal to the way ORM's work.我相信他建议您研究 ORM 的原因是因为您的设计实际上与 ORM 的工作方式在原则上非常相似。 They are abstracted classes that represent tables in your database that can be easily queried with LINQ.它们是代表数据库中的表的抽象类,可以使用 LINQ 轻松查询。 LINQ queries are automatically parameter-ized and relieve you of the stress of managing the security of your queries. LINQ 查询会自动参数化,从而减轻您管理查询安全性的压力。 They generate SQL on the fly (the same way you are when you pass strings to your data-access class) and are much more flexible in the way they can return data (arrays, lists, you name it).它们即时生成 SQL(与您将字符串传递给数据访问类时的方式相同),并且在返回数据的方式(数组、列表,您可以命名)方面更加灵活。

One drawback to the ORM's, however, is that they have pretty steep learning curves.然而,ORM 的一个缺点是它们的学习曲线非常陡峭。 A simpler option (though a bit older than EF) would be to use Typed Datasets.一个更简单的选择(虽然比 EF 旧一点)是使用类型化数据集。 Typed Datasets are much easier to create than standing up ORM's and are generally much easier to implement.类型化数据集比建立 ORM 更容易创建,并且通常更容易实现。 Though not as flexible as ORM's, they accomplish exactly what you're trying to do in a simple, safe,and already solved manner.虽然不如 ORM 灵活,但它们以简单、安全且已经解决的方式准确地完成了您想要做的事情。 Fortunately, when ASP.NET first came out training videos focused heavily on typed datasets and as such there are a variety of high quality freely available videos/tutorials to get you up and running quickly.幸运的是,当 ASP.NET 首次出现时,培训视频主要侧重于类型化数据集,因此有各种高质量的免费视频/教程可以帮助您快速上手。

You are on the right track, and I have actually done what you are looking for myself too.你走在正确的轨道上,我实际上也已经完成了你自己正在寻找的事情。 However, instead of just passing in a string to your function, I pass in a SQL Command object... So this way, you can properly build out all your commands and parameters and then say ... here, go run this, it is ready to go.但是,我不只是将字符串传递给您的函数,而是传递一个 SQL Command 对象……这样,您就可以正确构建所有命令和参数,然后说……在这里,运行它,它准备好了。 Something like就像是

public static DataTable SqlDataTable(SqlCommand cmd)
{
    using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
    {  
        cmd.Connection = conn;   // store your connection to the command object..
        cmd.Connection.Open();
        DataTable TempTable = new DataTable();
        TempTable.Load(cmd.ExecuteReader());
        return TempTable;
    }
}

public DataTable GetMyCustomers(string likeName)
{
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "select * from SomeTable where LastName like "@someParm%";
    cmd.Parameters.Add( "whateverParm", likeName );  // don't have SQL with me now, guessing syntax

    // so now your SQL Command is all built with parameters and ready to go.
    return SqlDataTable( cmd );
}

My suggestion: use an orm.我的建议:使用 orm。 There are plenty to choose from now a days现在有很多可供选择的日子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM