• 学习笔记-java代码审计-sqli


    Java代码审计-sqli

    0x01 漏洞挖掘

    jdbc

    在上古时期,人们往往这么从数据库获取数据。

    1. public User getUserById(String id) throws SQLException {
    2. Connection connection = JDBCTOOLS.getConnection();
    3. String sql = "select id,username from user where id=" + id;
    4. Statement statement = connection.createStatement();
    5. ResultSet resultSet = statement.executeQuery(sql);
    6. resultSet.next();
    7. int userId = resultSet.getInt(1);
    8. String username = resultSet.getString(2);
    9. User user = new User(userId, username);
    10. return user;
    11. }

    通过拼接字符串来构建sql语句,其中又有用户可控的部分,很容易出现问题。

    后来,出现了预编译机制,但是预编译只能处理查询参数,很多场景下仅仅使用预编译是不够的。

    • like

      在使用模糊查询的场景中,

      String sql = "select * from user where username like '%?%'";

      这种写法是无法进行预编译的,程序会报错。

    • order by

      需要按照时间、id等信息进行排序的时候,也是无法使用预编译的。

      1. String sort = req.getParameter("sort");
      2. String sql = "select * from user order by ?";
      3. PreparedStatement preparedStatement = connection.prepareStatement(sql); //预编译
      4. preparedStatement.setString(1, sort); //绑定参数
      5. ResultSet resultSet = preparedStatement.executeQuery();

      如果像上面这样强行使用预编译,数据库会将字段名解析为字符串,即实际执行的sql为

      select * from user order by 'username';

      无法达到实际需求。

    Hibernate
    1. @Autowired CategoryDAO categoryDAO; //依赖注入
    2. @RequestMapping("/hibernate")
    3. public String hibernate(@RequestParam(name = "id") int id) {
    4. Category category = categoryDAO.getOne(id);
    5. return category.getName();
    6. }

    hibernate即我们经常使用的orm的一种实现,如果使用已封装好的方法,那么默认是使用预编译的。需要注意的有这么几种情况:

    1. 对于一些复杂的sql语句,需要开发手写sql,此时要严格过滤用户输入。
    2. 上面提到的预编译不生效的几种场景。
    Mybatis

    mybatis有两种写法,一种是基于注解:

    1. @Mapper
    2. public interface CategoryMapper {
    3. @Select("select * from category_ where name= '${name}' ")
    4. public CategoryM getByName(@Param("name") String name);
    5. }

    另一种是基于xml:

    1. "1.0" encoding="UTF-8"?>
    2. mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="cn.seaii.springboot.mapper.CategoryMapper">
    6. <select id="get" resultType="cn.seaii.springboot.pojo.CategoryM">
    7. select * from category_ where id= ${id}
    8. select>
    9. mapper>

    注意在maven项目中,xml文件要放在resources目录中。

    0x02 漏洞防御

    2.1 类型转换

    java是一门强类型的语言,所以数字型注入一般很少出现,但还是要有必要的类型转换。

    比如通过HttpServletRequest的getParameter方法获取到的参数的类型都是String。

    int id = Integer.valueof(req.getParameter("id"));
    2.2 预编译

    无论那种web编程语言,目前防注入最通用、最流行的方法就是使用预编译。

    1. public User getUserById(String id) throws SQLException {
    2. Connection connection = JDBCTOOLS.getConnection(); //获取连接,细节省略
    3. String sql = "select id,username from user where id=?";
    4. PreparedStatement preparedStatement = connection.prepareStatement(sql); //预编译
    5. preparedStatement.setString(1, id); //绑定参数
    6. ResultSet resultSet = preparedStatement.executeQuery();
    7. resultSet.next();
    8. int userId = resultSet.getInt(1);
    9. String username = resultSet.getString(2);
    10. User user = new User(userId, username);
    11. return user;
    12. }

    在使用预编译之后,即使用户提交的参数中含有敏感关键字(union、select等),数据库也会将其作为对应字段的值来处理而不会解析其中的sql关键字。

    mybatis中这样写:

    1. @Mapper
    2. public interface CategoryMapper {
    3. @Select("select * from category_ where name= #{name} ")
    4. public CategoryM getByName(String name);
    5. }

    看起来比不使用预编译还要简单一点。

    2.3 其他防御

    上面也提到过,预编译只能处理查询参数,对于其他位置存在用户可控的情况(order by、in、like等),无法提供有效的保护,此时就要具体情况具体分析。

    以上面提到的两种情况为例:

    1. //like
    2. String sql = "select * from user where username like concat('%', ?, '%')";
    3. //预编译

    order by可以设置白名单,只有白名单中的字段才可以拼接。

    1. private String checkSort(String sortBy) {
    2. List columns = new ArrayList<>(Arrays.asList("id", "username"));
    3. return (columns.contains(sortBy)) ? sortBy : "''";
    4. }

    0x03 参考资料

    Mybatis框架下SQL注入漏洞面面观

    点击关注,共同学习!安全狗的自我修养

    github haidragon

    https://github.com/haidragon

  • 相关阅读:
    java图片转pdf ,pdf 导出
    高薪程序员&面试题精讲系列130之说说你对微服务的理解?SpringCloud中有哪些常用的组件和注解?
    vue3基于vite打包
    81 # 多语言
    Linux网络编程- IO多路复用
    UG\NX二次开发 选择基准平面 UF_UI_select_with_single_dialog
    【大数据 | 综合实践】大数据技术基础综合项目 - 基于GitHub API的数据采集与分析平台
    你不知道的 HTML 属性
    RTC-实时音视频通信技术介绍与应用
    Python实用模块之argparse
  • 原文地址:https://blog.csdn.net/sinat_35360663/article/details/127828676