当前位置: 首页 > news >正文

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

🍬 博主介绍

👨‍🎓 博主介绍:大家好,我是 _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数据库下载

相关文章:

  • 汽车OTA概述
  • 基于Java+Swing+mysql餐厅点餐管理系统
  • 店铺如何快速实现数字化管理?不妨参考一下管理系统
  • 修改后的代码只进行了git add操作不小心给他恢复了怎么找回来
  • JUC(一):线程池
  • org.springframework.jdbc.BadSqlGrammarException: Error updating database
  • 熟人服务器被黑,五种实战方法强化linux服务器安全性!
  • RabbitMQ总结
  • 【每日一题Day67】LC1739放置盒子 | 找规律+贪心 二分查找
  • 【Linux】Linux项目自动化构建工具——make/Makefile
  • <Linux线程同步>——《Linux》
  • 【Array数组】面试前基础知识点深度记忆总结
  • 20221226编译Toybrick的TB-RK3588X开发板的Android12系统1-编译环境配置
  • 大话JMeter2|正确get参数传递和HTTP如何正确使用
  • 在Makefile中使用空格缩进的方法
  • 0x05 Python数据分析,Anaconda八斩刀
  • CSS盒模型深入
  • ES6核心特性
  • exif信息对照
  • iOS小技巧之UIImagePickerController实现头像选择
  • Java知识点总结(JavaIO-打印流)
  • leetcode388. Longest Absolute File Path
  • Linux快速复制或删除大量小文件
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • node 版本过低
  • springboot_database项目介绍
  • 阿里云Kubernetes容器服务上体验Knative
  • 从零开始的无人驾驶 1
  • 区块链将重新定义世界
  • 深度学习在携程攻略社区的应用
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • ionic入门之数据绑定显示-1
  • MPAndroidChart 教程:Y轴 YAxis
  • 关于Android全面屏虚拟导航栏的适配总结
  • 浅谈sql中的in与not in,exists与not exists的区别
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #{}和${}的区别?
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (C++20) consteval立即函数
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (附源码)计算机毕业设计高校学生选课系统
  • (过滤器)Filter和(监听器)listener
  • (十)c52学习之旅-定时器实验
  • (转)Mysql的优化设置
  • **PHP分步表单提交思路(分页表单提交)
  • .net 托管代码与非托管代码
  • .net通用权限框架B/S (三)--MODEL层(2)
  • @ConditionalOnProperty注解使用说明
  • @GlobalLock注解作用与原理解析
  • [ACTF2020 新生赛]Upload 1
  • [AIGC 大数据基础]hive浅谈
  • [Android]使用Git将项目提交到GitHub
  • [BZOJ3757] 苹果树
  • [hdu 1247]Hat’s Words [Trie 图]