一、什么是SQL注入攻击
SQL注入顾名思义也就是在某个东西中插入了SQL语句,如果这些恶意的SQL语句一旦执行,那么就会对我们的应用程序照成破坏,这其实就是SQL注入攻击。
那么为什么会产生SQL注入攻击呢?据我总结,大致可以分为以下几点原因:
*使用字符串拼接sql语句
*在应用程序连结数据库时使用权限过大的帐户(sa)
*在数据库中开放了不必要但权力过大的功能(xp_cmdshell)
*未过滤用户的恶意输入
===============================================
如果要对一个网站进行SQL注入攻击,首先就需要找到存在SQL注入漏洞的地方,也就是寻找所谓的注入点。可能的SQL注入点一般存在于登录页面、查找页面或添加页面等用户可以查找或修改数据的地方。最常用的寻找SQL注入点的方法,是在网站中寻找如下形式的页面链接:http://www.xxx.com/xxx.asp?id=YY,其中“YY”可能是数字,也有可能是字符串,分别被称为整数类型数据或者字符型数据。
这里我们不谈如何攻击成功,我们只谈思路。所以,我这样不算是教坏你们。首先,注入不一定要这样的地址才能注入。任何一个于数据库交互的地方都有可能注入。这句话怎么理解?且听我慢慢道来:
二、案例演示
1、以我自己写的一个登录为例子

这是登录后台。
这个时候需要我们填写帐号和密码。可问题是我们不知道帐号和密码。怎么办??????
注入!!!
那么,一般这个时候,没有安全意识的程序员后台代码会这样写!
下面的前端提交页面
- function user_input() {
- var name = $("#id").val();
- var password = $("#password").val();
- if (name == "" || password == "") {
- showToast("帐号和密码不能为空");
- return;
- } else {
- $.post("BackProcess/Login.ashx", { "action": "login", "user": name, "pass": password }, function (data) {
- if (data == "1") {
- top.location.href = "admin/Company.htm";
- }
- else if (data == "0") {
- top.location.href = "admin/ArtistUI.htm";
- }
- else {
- showToast("帐号或密码错误!");
- }
- });
- }
- }
复制代码
解释下 这里是通过 ajax的方式提交用户输入的帐号和密码到后台页面。后台页面进行处理完毕之后返回结果。根据结果来判断跳转的页面。
这个提交写的好像没什么问题,我们看看后台代码
- public void ProcessRequest(HttpContext context)
- {
- context.Response.ContentType = "text/plain";
- string ActionString = context.Request.Form["Action"];
- switch (ActionString)
- {
- case "login": { UserLogin(context); } break;
- case "Logout": { LogOut(context); } break;
- case "checklogin": { IsLogin(context); } break;
- default:
- break;
- }
- }
复制代码 这里是后台处理提交业务的代码,这里好像没什么问题。我们接下来继续看。
- void UserLogin(HttpContext context)
- {
- string username = context.Request.Form["user"];
- string password = context.Request.Form["pass"];
- string sql = string.Format(@"select UserType from M_Users where UserName='{0}' and PassWord='{1}'", username, password);
- object obj = Dal.DBHelper.GetScaler(sql);
- if (obj == null)
- {
- context.Response.Clear();
- context.Response.Write("-1");
- context.Response.End();
- }
- else
- {
- //写COOKIE
- CookieHelper.WriteCookie(context, username + "," + obj.ToString());
- sql = string.Format(@"update M_Users set LastLoginDate = getdate() where UserName='{0}' and PassWord='{1}'", username, password);
- Dal.DBHelper.ExecuteNonQuery(sql);
- context.Response.Clear();
- context.Response.Write(obj.ToString());
- context.Response.End();
- }
- }
复制代码 这里是具体的业务处理。我们可以看到传过来的帐号和密码没有经过任何的处理直接拼接到了SQL中。这就是一个注入点。
我们通过构建特殊的SQL来达到目的 (这需要有SQL基础)
我们知道 提交到数据库的sql语句是这样的
- select UserType from M_Users where UserName='admin' and PassWord='admin'
复制代码 我们假设帐号密码是admin 就可以成功登录。可我们是干嘛的,我们是来注入的,是来干坏事的,所以!
开始构建特殊SQL进行注入。
我们把SQL变成这样
- select UserType from M_Users where UserName='' or '1'='1' and PassWord='' or '1'='1'
复制代码
那么 我们传入的帐号和密码就是 ' or '1'='1 这样 无论如何 WHERE后面的条件都会满足,所以一定会有结果返回。于是我们登录成功了。

2、案例二
下面我们来看一段代码:
-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Data;
namespace sqlInjectionTest.admin
{
public partial class Login1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
using (SqlConnection con = new SqlConnection(@"Integrated Security=SSPI;Persist Security Info=False;Data Source=.\SQLEXPRESS;Initial Catalog=Manage"))
{
con.Open();
if (ConnectionState.Open==con.State)
{
//Response.Write("<script>alert('连接数据库成功!')</script>");
string username = tb_Name.Text.Trim().ToString();
string password = tb_PassWord.Text.Trim().ToString();
string sql_cmd ="select * from Admin where Name='"+username+"' and Pwd='"+password+"'";
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = sql_cmd;
cmd.Connection = con;
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
//Response.Write("<script>alert('登录成功!')</script>");
Session["US"] = username;
Response.Redirect("./LoginIndex.aspx");
}
else
{
Response.Write("<script>alert('登录失败!')</script>");
}
reader.Close();
}
}
}
else
{
Response.Write("<script>alert('连接数据库失败!')</script>");
}
}
}
}
}
复制代码
=========================================================
我们在用户登录的用户名处写:'or'1'='1'--

- string sql_cmd = "select * from Admin where Name='" + username + "'"+"and Pwd='"+password+"'";
复制代码
则我们原本执行的SQL语句变为:
- select * from Admin where Name=''or'1'='1'--' and Pwd=''
复制代码

这就是一个最简单的SQL注入攻击!
三、一般检测方法
1、.“加引号”法
在浏览器地址栏中的页面链接地址后面增加一个单引号,如下所示:
http://www.xxx.com/xxx.asp?id=YY’
然后访问该链接地址,浏览器可能会返回类似于下面的错误提示信息:
Microsoft JET Database Engine 错误’80040e14’
字符串的语法错误在查询表达式’ID=YY’中。
/xxx.asp 行8
如图1.3所示,页面中如果返回了类似的错误信息,说明该网站可能存在SQL注入攻击的漏洞。

2、.“1=1和1=2”法
“加引号”法很直接,也很简单,但是对SQL注入有一定了解的程序员在编写程序时,都会将单引号过滤掉。如果再使用单引号测试,就无法检测到注入点了。这时,就可以使用经典的“1=1和1=2”法进行检测。
如果正常页面链接地址为:http://www.xxx.com/xxx.asp?id=YY,在浏览器中分别输入以下两个链接地址,分别查看它们返回的结果值。
? http://www.xxx.com/xxx.asp?id=YY and 1=1。
? http://www.xxx.com/xxx.asp?id=YY and 1=2。
如果存在注入点的话,浏览器将会分别显示为:
? 正常显示,内容与正常页面显示的结果基本相同。
? 提示BOF或EOF(程序没做任何判断时),或提示找不到记录,或显示内容为空(程序加了on error resume next),如图1.4所示。
如果没有注入点的存在,也很容易判断。
上述两种链接一般都会有程序定义的错误提示,或提示类型转换时出错。
