代码审计入门之SQL注入原理及分析

初识Java代码审计,所以分析比较稚嫩,大佬请绕行。本篇分析SQL 注入漏洞原理。前一段时间在总结SQL Server的注入漏洞时,自己编写了一套靶场(java+SQL Server+tomcat+win10),正好用于本篇文章的分析。

相关文章:

留言板项目下载地址
代码审计入门之前篇
代码审计入门之XSS原理及分析
代码审计入门之CSRF原理及分析

0x00 原理

所谓 SQL 注入,就是通过将 SQL 命令插入应用程序的 http 请求中,并在服务器端被接收后用于参与数据库操作,最终达到欺骗服务器执行恶意的 SQL 命令的效果,Java 的 SQL 注入和 PHP 中的 SQL 注入,其实差别不大,理论上来讲,应用程序中只要是与数据库存在数据交互,无论是增删改查,只要传入的数据可受用户控制,且对用户传入的数据没有进行过滤或过滤不严格,那么都是可能存在 SQL 注入的。

0x01 挖掘技巧

SQL注入原理其实很简单,在代码中体现的有以下3点:

  1. 传递的参数为用户可控;
  2. 系统未对传入后台的参数做任何特殊字符过滤,或者字符过滤不全。

    对SQL注入而言,特殊字符包括(注意大小写):
    --,#,//(注释符)、and、or、select
    update、delete、drop、declare、insert、xp_shell
    (,)括号、||,+, (空格) 连接符、 ' 单引号、|(竖线符号)、& (& 符号)
    、;(分号)、$(美元符号)、%(百分比符号) 、@(at 符号)、"(引号)
    '(反斜杠转义单引号)、"(反斜杠转义引号)、<>(尖括号)、CR(回车符,ASCII 0x0d)、LF(换行,ASCII 0x0a)、,(逗号)、(反斜杠)

  3. SQL语句是以拼接的形式执行,代码如下所示:
 String sql="select * from test where id="+id;

挖掘的时候只要是与数据库存在数据交互,无论是增删改查,只要传入的数据可受用户控制,且对用户传入的数据没有进行过滤或过滤不严格,那么都是可能存在 SQL 注入的。

0x02 漏洞原理分析

SQL注入的类型又分为联合查询注入、报错注入、盲注等,其实原理都差不多,就不按个介绍了,以联合查询注入为例:
页面如下;
1.png

分析代码:

查看int.jsp页面:可以看到在 sql 语句中,存在着拼接的String类型变量id,且没有进行任何的过滤处理,直接带入执行。

2.png

这也就导致了 SQL 注入,如下图,带入参数and 1=1
为了方便查看,sql语句直接输出到页面上。可以得知,我们传入的参数完整的带入了sql查询语句中:

3.png

由此,这个地方已经可以判断存在SQL 注入了。

SQL语句一旦以拼接的方式执行,就表示拼接的参数“ 1 and 1=1”是表示一个SQL语句,而不仅仅是作为一个参数执行,什么意思呢?详细如下:
如果id的值为1,那么SQL语句变成: select * from login where id=1
如果word的值为1 and 1=1,那么SQL语句变成:select * from login where id=1 and 1=1

最后在数据库中执行的时候就是:select * from login where id=1 and 1=1

0x03 漏洞防御

之所以造成 SQL 漏洞的原因,是程序将用户输入数据拼接到了 SQL 语句中,那么如何修复便容易明白。

1、使用预编译

在Java的JDBC中,有个预处理功能,这个功能一大优势就是能提高执行速度,尤其是多次操作数据库的情况,再一个优势就是预防SQL注入,严格的说,应该是预防绝大多数的SQL注入。
下方代码就是利用 java 的预编译来防止 SQL 注入(此代码来自自己编写的留言板:):
此代码中在和数据库做连接的地方采用预处理的方式

4.png

需要注意的是,预编译不是绝对安全的,是要看所使用的具体的 SQL 语句的,例如下述代码:
类似于下面代码中的 SQL 语句,order by 后的参数,是不能够用预编译进行处理的,只能通过拼接进行操作,因此需要手动过滤。

//查询
    public ArrayList<Ly> showLy(Connection con) throws Exception{ 
         ArrayList<Ly> list=new ArrayList<Ly>();
         String sql="select * from ly where lyid=?"+"order by"+ lyname;
         try {
                    PreparedStatement ps=con.prepareStatement(sql);
                    ps.setInt(1, ly.getLyid());
                ResultSet rs=ps.executeQuery();
                while(rs.next()){
                    Ly ly=new Ly();
                    ly.setLyid(rs.getInt("lyid"));
                    ly.setContent(rs.getString("content"));
                    ly.setLyname(rs.getString("lyname"));
                    ly.setTime(rs.getString("time"));
                    list.add(ly);
                }               
         }catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
         return list;
    }                

以上,只是基于 java servlet上来解释 SQL 注入,但实际上在真实环境中,中间件框架使用占了绝大部分,但实际上原理基本类似,只是表面形式不同,如 Mybatis 框架中的 like、 in和 order by 语句、Hibernate 框架中的 createQuery()函数等,如果使用不当,依旧可能造成 sql 注入。

2、使用全局过滤器

添加全局过滤器,过滤特殊字符;方式如下:

5.png

6.png

0x04 参考链接:
https://xz.aliyun.com/t/6872
https://www.cnblogs.com/ichunqiu/p/7281384.html

标签: none

仅有一条评论

  1. 菜鸟路过

    可以

添加新评论