zoukankan      html  css  js  c++  java
  • JAVA审计SQL注入

    0x00 前言

    记录一下学习java审计的过程。

    0x01 JDBC方式

    1. 三个对象:

    • connection

      connection对象代表数据库

      可以设置数据库自动提交。事务提交(connection.commit()),事务回滚(connection.rollback())。

    • statement

      调用connnection.createStatement()方法会返回一个statement对象。

      是具体执行sql语句

    • PreparedStatement

      与statement对象的区别是,不直接放入sql语句,先用?作为占位符进行预编译,等预编译完成后,对?进行赋值,之后调用execute等方法不需要添加参数即可完成执行SQL语句。

    所以我们在使用JDBC的时候,使用statement直接拼接SQL语句可能会造成SQL注入。

    2. 举例

    request.getParameter("userId")
    
    private String getNameByUserId(String userId) {
        Connection conn = getConn();//获得连接
        String sql = "select name from user where id=" + userId;
        Statement stmt =  conn.createStatement();
        ResultSet rs=stmt.executeUpdate(sql);
    }
    

    上面的代码没有经过预编译,然后直接拼接前段获取的参数到sql语句后执行,会产生sql注入;

    这边还有另外一个例子:

    request.getParameter("userId")
    
    private String getNameByUserId(String userId) {
        Connection conn = getConn();//获得连接
        String sql = "select name from user where id=" + userId;
        PreparedStatement pstmt =  conn.prepareStatement(sql);
        ResultSet rs=pstmt.executeUpdate();
    }
    

    这样虽然使用了PreparedStatement,但是没有规范的使用预编译,同样是拼接的方式也会造成sql注入问题;

    下面是规范的采用预编译的方式:

    //安全的,预编译的,防止了sql注入
    Connection conn = getConn();//获得连接
    String sql = "select id, username, password, role from user where id=?"; //执行sql前会预编译号该条语句
    PreparedStatement pstmt = conn.prepareStatement(sql); 
    pstmt.setString(1, id); 
    ResultSet rs=pstmt.executeUpdate();
    

    0x02 Mybatis

    Mybatis回顾

    • mybatis的maven配置

      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.2</version>
      </dependency>
      
    • config.xml 配置数据库连接的文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE configuration
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
          <environments default="dev">
              <environment id="dev">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                      <property name="url"
                                value="jdbc:mysql://localhost:3306/mybatistest"/>
                      <property name="username" value="root"/>
                      <property name="password" value="123456"/>
                  </dataSource>
              </environment>
          </environments>
          <mappers>
              <mapper resource="UserMapper.xml"/>
          </mappers>
      </configuration>
      

      主要注意配置文件中注册的xml,获取值的方式有两种,分别是${}#{}

      区别:

      "#{}"将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,属于正确的预编译,输入的参数会全部变成查询的部分;

      "${}"将传入的数据直接拼接在sql中,造成sql注入。如where username={username},如果传入的值是111,那么解析成sql时的值为where username=111;如果传入的值是1 and 1=1 ;,则解析成的sql为:select id, username, password, role from user where username=1 and 1=1。

    MyBatis容易产生问题的三个地方

    1. like模糊查询

    在Mybatis中使用like进行模糊查询:

    Select * from news where title like ‘%#{title}%’
    

    但是这种写法会报错抛异常,这种时候把#改成$能正常运行,但是也产生了安全问题;

    正确写法:

    select * from news where tile like concat(‘%’,#{title}, ‘%’)
    

    2. in 之后的多个参数

    in之后多个id查询时使用# 同样会报错

    Select * from news where id in (#{ids})
    

    正确用法为使用foreach,而不是将#简单替换为$

    id in<foreach collection="ids" item="item" open="("separatosr="," close=")">#{ids} </foreach>
    

    3. order by之后

    Select * from news where title ='#{titlename}' order by #{time} asc
    

    需要注意order by之后通过#执行也会报错,使用order by语句时是无法使用预编译的,原因是order by子句后面需要加字段名或者字段位置,而字段名是不能带引号的,否则就会被认为是一个字符串而不是字段名,然而使用PreapareStatement将会强制给参数加上',所以还要在过滤上做好防御的准备

    正确写法:

    Select * from news where title ='#{titlename}' order by ${time} asc
    

    所以审计时候可以多观察这几个容易出现问题的地方。

    总结:可以使用idea 搜索$关键字,先筛选xml文件搜索$,逐个分析,要特别注意mybatis-generator的order by注入,全局搜索调出Find in Path,筛选后缀xml,搜索$关键字,找到是mybatis的数据库文件,找到调用函数后,⌘+f7查看调用链,检查中间是否被过滤

    参考

    https://www.cnblogs.com/CoLo/p/15225346.html

    https://www.cnblogs.com/nice0e3/p/13647511.html

    https://zeo.cool/2020/07/24/java代码审计自学:sql注入篇/

    https://xz.aliyun.com/t/10686

    https://cloud.tencent.com/developer/article/1123127

  • 相关阅读:
    使用XMLReader读XML
    C#命名空间大全详细教程
    C# using 三种使用方式
    SVN服务器搭建
    简单的自定义Session
    python学习第十八天 --错误&异常处理
    锁的等级:方法锁、实例锁、类锁
    java线程池如何合理的设置大小
    挖掘两个Integer对象的swap的内幕
    实现线程同步的方式
  • 原文地址:https://www.cnblogs.com/N0r4h/p/15743200.html
Copyright © 2011-2022 走看看