一、SQL字符串注入攻击
SQL注入攻击俗称为黑客的填空游戏是黑客对数据库进行攻击的常用手段之一。SQL注入的手法相当灵活,SQL注入攻击会导致的数据库安全风险包括:刷库、拖库、撞库。 一般来说,SQL注入一般存在于形如:HTTP://xxx.xxx.xxx/abc.asp?id=XX等带有参数的ASP动态网页中,如果ASP程序员没有安全意识,不进行必要的字符过滤,存在SQL注入的可能性就非常大。
1、攻击思路
发现SQL注入位置;
判断后台数据库类型;
确定XP_CMDSHELL可执行情况
发现WEB虚拟目录
上传ASP木马;
得到管理员权限;
2、攻击操作(1)向数据库添加数据(使用上一章对数据库添加操作)
///攻击前 字符串拼接形式[ " +code+ " ', ' " +name+ " ] 添加数据 cmd.CommandText = "insert into Students values( ' " +code+ " ', ' " +name+ " ' )"; conn.Open(); cmd.ExecuteNonQuery(); conn.Close(); /// SQL注入攻击 // 将原字符串"name" 部分改变拼接 // 拼接语句的最后的 “--” 注释掉了原拼接字符串后面的部分 a ' ) ; update students set Sname = ' 傻 X ' ;-- /// 攻击后 实际运行 cmd.CommandText = "insert into Students values ( ' code' ,' a ' ); update students set Sname = ' 傻 X ' ; -- conn.Open(); cmd.ExecuteNonQuery(); conn.Close();
(2)对有登录页面的网站进行注入攻击
//某个网站的登录验证的SQL查询代码为: strSQL = "SELECT * FROM users WHERE (name='" + userName+"') and (pw= '"+ passWord +"');" //恶意填入 userName = "1' OR '1'='1"; passWord = "1' OR '1'='1"; //将导致原本的SQL字符串被填为 strSQL = "SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');" //也就是实际上运行的SQL命令会变成下面这样的 strSQL = "SELECT * FROM users;" //达到无账号密码,亦可登录网站。
二、使用占位符防注入攻击
1、防攻击的方法:
可以通过数据库防火墙实现对SQL注入攻击的防范,,
可以使用虚拟补丁技术实现对注入攻击的SQL特征识别,实现实时攻击阻断。
在构造动态SQL语句时,一定要使用占位符这将防止有人试图偷偷注入另外的SQL表达式
2、占位符防注入攻击使用
对攻击案例1进行防御
cmd.CommandText = "insert into Students values(@a,@b)"; cmd.Parameters.Clear(); // 清空 cmd.Parameters.AddWithValue( " @a " , code ); //@a 占位符 与对应的值 code cmd.Parameters.AddWithValue( " @b " , name ); //@b 占位符 与对应的值 name conn.Open(); cmd.ExecuteNonQuery(); conn.Close();
Parameters 集合是属于数据库操作类的,作用是防止字符串注入攻击
public List<Users> select(string name) { List<Users> list = new List<Users>(); cmd.CommandText = "select * from Car where name like @a"; cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("@a",'%'+name+'%'); conn.Open(); SqlDataReader dr = cmd.ExecuteReader(); while (dr.Read()) { Users u = new Users(); u.Name = dr["name"].ToString(); list.Add(u); } conn.Close(); return list; }
3、练习
Student表 Scode,Sname
添加学生信息 ,只需要用户输入学生姓名,
编号自动生成:S001 S002 .....
1
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.SqlClient; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { //默认表中没有数据 string code = "S001"; while (true) { Console.Write("请输入添加的学生姓名:"); string name = Console.ReadLine(); string sql = "server=.;database=Data0216;user=sa;pwd=123"; SqlConnection conn = new SqlConnection(sql); SqlCommand cmd = conn.CreateCommand(); //查询所有降序排列 cmd.CommandText = "select *from Students order by Scode desc"; conn.Open(); SqlDataReader dr = cmd.ExecuteReader(); if (dr.HasRows) { //生成编号 dr.Read(); //取第一个(最大) string s = dr["Scode"].ToString(); // 截取 s 后面的 转换类型 留3位数 code = "S" + (Convert.ToInt32(s.Substring(1)) + 1).ToString("000"); } conn.Close(); cmd.CommandText = "insert into Students values(@a,@b);"; cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("@a", code); cmd.Parameters.AddWithValue("@b", name); conn.Open(); cmd.ExecuteNonQuery(); conn.Close(); Console.ReadLine(); } } } }
2
using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Text; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { //5、Student表 Scode,Sname //添加学生信息 ,只需要用户输入学生姓名, //编号自动生成:S001 S002 string sql = "server=.;database=Data0216_5;user=sa;pwd=123"; SqlConnection conn = new SqlConnection(sql); SqlCommand cmd = conn.CreateCommand(); Console.Write("请输入姓名:"); string name = Console.ReadLine(); string scode; cmd.CommandText = "select * from student"; conn.Open(); SqlDataReader dr = cmd.ExecuteReader(); if (dr.HasRows) { int a = 0; while (dr.Read()) { a += 1; } scode = "s" + (a+1).ToString("000"); } else { scode = "s001"; } conn.Close(); cmd.CommandText = "insert into student values('" + scode + "','" + name + "')"; conn.Open(); int aa = cmd.ExecuteNonQuery(); if (aa > 0) { Console.WriteLine("添加成功"); } else { Console.WriteLine("添加失败!"); } conn.Close(); Console.ReadLine(); } } }
1于2的区别
1 中先找最大号,新加入的比最大号大 1
2 中先看有多少记录,新加入的比总记录数大 1