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






4.85/5 (65投票s)
本文描述了什么是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注入 -
- 验证用户输入(使用正则表达式或其他方式)
- 使用参数化查询
- 使用存储过程
- 使用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注入。