65.9K
CodeProject 正在变化。 阅读更多。
Home

保护您的ASP.NET应用程序免受SQL注入攻击

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (65投票s)

2013年6月7日

CPOL

4分钟阅读

viewsIcon

138546

downloadIcon

2407

本文描述了什么是SQL注入以及如何防止SQL注入。

引言

开发者都不希望自己的Web应用程序被黑客攻击。但入侵者、恶意攻击者比开发者要多,我曾经也是其中一员,然后才转变为开发者。因为我亲身体验过,所以我决定写一系列的文章,这些文章肯定有助于Web应用程序的防黑客攻击。

开发者应该时刻关注应用程序中的黑客攻击尝试,这也是开发者的职责。互联网上有很多在线工具、欺骗工具、嗅探器工具等。所以即使是一个普通的互联网用户也能变成黑客。我希望每个人都知道被黑客攻击的后果,所以在此不再赘述,我还是写我的文章吧。

让我们开始了解一些黑客攻击以及开发者如何防止它们。在这第一篇文章中,我将从SQL注入开始。

SQL 注入

SQL注入是一种攻击,攻击者将一个或多个命令插入到查询中,形成一个危险的查询,该查询可能会检索、损坏、篡改您现有的数据通道。这种情况几乎总是发生在使用了动态SQL并且您在代码(C#、VB、J#、F#)中连接字符串来构建SQL语句时。如果您的Microsoft .NET Framework代码正在构建查询或过程调用,就会发生SQL注入,并且在服务器端T-SQL代码中也可能发生,例如存储过程中的动态SQL。

SQL注入是2010年的头号攻击。遗留代码的应用程序仍然容易受到SQL注入的攻击。让我更清楚地描述,或者说用简单的语言来说,当命令(或其他SQL查询)被插入到我们本应发送数据的SQL语句中时,就会发生这种情况。我们可以将整个查询分为两个通道:控制通道(查询)和数据通道(用户输入)。攻击者通常不关心您的控制通道(查询),他只关心如何将恶意查询插入到您的数据通道中。

还有其他方法可以进行SQL注入 : -

  • SQL函数中的字符串截断
  • 自动化工具

除了劫持任何个人或团体账户之外,SQL注入可以帮助您完成权限允许的几乎所有系统操作 : -

  • 安装后门
  • 可以通过80端口复制数据库
  • 端口扫描(可以扫描您的整个网络)
  • 还有更多!!

如何利用它 -

通常,攻击者直接从网页注入SQL注入,或通过操纵SQL语句进行注入。

在上面的代码中,我们将字符串与用户输入数据连接起来,形成SQL语句。我们的查询应该像下图一样工作 -

但黑客的想法不同,他会像下图一样操纵查询 -

上面示例中使用的SQL注入 -

' union select username , password ,'1' from [User] --' 

以上只是一个例子,黑客可以在应用程序上尝试许多SQL注入。黑客可以获取密码,安装后门。黑客可以操纵查询以从sysobject中获取所有数据库的详细信息。

如何防止SQL注入 -

  1. 验证用户输入(使用正则表达式或其他方式)
  2. 使用参数化查询
  3. 使用存储过程
  4. 使用ORM

1.验证用户输入

最简单的方法是使用正则表达式验证用户输入,并将危险字符替换为空格。

//Validate the user input
string userinput = TextBox1.Text;
 
//only accept the alphabets and numbers , rest will be replaced by blank    
userinput = Regex.Replace(userinput, "[^A-Za-z0-9$]", ""); 

但是,这并不是防止应用程序SQL注入的最佳方法。因为SQL注入不只包含“ - ”或“ ' ”。有很多SQL注入包含合法的代码。

2.使用参数化查询 -

如果我们想使用内联SQL,那么为了阻止SQL注入,我们可以将参数传递给SQL查询,并在查询中添加SQL参数。通过这种方式,我们可以防止SQL注入。使用SQL语句内联并没有什么错。

string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
//add the parameter in query
string query = string.Format(@"select Username ,Age,Department from " + 
       @"[User] where Username like '%+@Username+%'", TextBox1.Text);

using (SqlConnection con = new SqlConnection(connectionString))
{
    //
    // Open the SqlConnection.
    //
    con.Open();
    //
    // The following code uses an SqlCommand based on the SqlConnection.
    //
    using (SqlDataAdapter da = new SqlDataAdapter())
    {
        using (SqlCommand command = new SqlCommand(query, con))
        {
            //pass the parameter
            command.Parameters.Add(new SqlParameter("@Username",TextBox1.Text)) ;
            DataSet ds = new DataSet();
            da.SelectCommand = command;
            da.Fill(ds, "test");
            GridView1.DataSource = ds;
            GridView1.DataBind();
        }
    }
}

参数化查询告诉SQL服务器,传递给任何参数的数据将保留在数据通道中,这就是SQL服务器防止SQL注入的方式。但这仍然不是最好的方法,因为我们将业务逻辑内联编写。每次我都要重新编写这个查询。

3.使用SQL存储过程 -

防止SQL注入的最佳方法是使用存储过程。因为业务逻辑被隐藏起来,它提供了更好的性能和可重用性。现在您只需要使用权限来保护表和存储过程。

string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
//add the stored procedure name 
string query = "dbo.GetUsername";

using (SqlConnection con = new SqlConnection(connectionString))
{
    //
    // Open the SqlConnection.
    //
    con.Open();
    //
    // The following code uses an SqlCommand based on the SqlConnection.
    //
    using (SqlDataAdapter da = new SqlDataAdapter())
    {
        using (SqlCommand command = new SqlCommand(query, con))
        {
            //pass the parameter
            command.Parameters.Add(new SqlParameter("@param1", TextBox1.Text));
            command.CommandType = CommandType.StoredProcedure;
            DataSet ds = new DataSet();
            da.SelectCommand = command;
            da.Fill(ds, "test");
            GridView1.DataSource = ds;
            GridView1.DataBind();
        }
    }
} 

4.使用ORM -

我们可以使用任何ORM(Entity framework,Nhibernate等)。ORM会在后台使查询参数化,所以通过使用ORM,我们也可以防止SQL注入。

参考文献

© . All rights reserved.