安全矩阵

 找回密码
 立即注册
搜索
查看: 1884|回复: 0

Java代码审计-sql注入基础篇

[复制链接]

249

主题

299

帖子

1391

积分

金牌会员

Rank: 6Rank: 6

积分
1391
发表于 2022-6-18 11:02:55 | 显示全部楼层 |阅读模式
简介:
本篇文件的标题虽然是sql注入,但只是简单描述一下sql注入点,以及注入产生的原因。大部分篇幅将介绍java 框架的特性、程序运行的流程以及环境的搭建。java常用的持久层框架有 mybatis、hibernate、jpa,持久层框架底层调用的是JDBC(Java Database Connectivity)Java数据库连接。

全篇一共5个章节,
第一章节演示了 Tomcat的创建到运行 以及Servlet的 运行流程、
第二章节将介绍Maven的重要性以及如何加载远程仓库、
第三章节将介绍JDBC中PreparedStatement()方法 与Statement()方法 的区别,以及环境的搭建,
第四章节将介绍Mybatis框架的使用场景,存在注入的原因,以及环境的搭建
第五章节将介绍Hibernate框架的使用场景,存在注入的原因,以及环境的搭建

环境准备
1、编辑工具:IntelliJ IDEA 2021.2.3
2、数据库使用Mysql ,创建一个数据库 demo 和一张表shops
3、IDEA使用到的插件 Chinese(中文插件)、Free Mybatis plugin(用于Mybatis 配置、对象生成)

第一章、javaWeb的项目搭建本人也是初学java代码审计,IDEA对于初学者并不是很友好,所以这里将JAVA项目的创建过程也记录了下来,供大家参考学习。

1、javaWeb 项目的创建     打开IDEA 文件>>新建>>项目
编辑
2、建立一个JavaEE的项目、需要修改的地方都圈出来了,没有下载tomcat、jdk的可以新建或者下载,版本的话尽量按照网上的教程保持一致,防止版本问题报错,之后下一步下一步就可以了。
编辑
3、项目创建好后,配置Tomcat 环境   运行>>编辑配置
编辑
编辑
编辑
4、运行Tomcat   打开浏览器访问  http://localhost:8080/
​​
编辑
5、项目差不多就搭好了,接下来简单介绍下Servlet,Servlet用于接收用户的请求,数据处理好后,把数据返回给前端,也可以不返回。
项目中有个HelloServlet.java文件可以打开来看看,文件目录:src->main->java->com.hacker.servlet ->HelloServlet。有个@WebServlet注解 ,value值 为用户访问的值,当用户访问
http://localhost:8080/hello-servlet时,会跳转到 这个Servlet 中,这里使用的是get请求,所以会执行doGet()方法里面的代码。
编辑

第二章、Maven介绍Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理,是一个自动化构建工具。
总之,Maven很强大,用起来很方便 后面要使用的依赖、环境都是用Maven来构建,只需要修改配置文件即可。可以把它看作是一个Jar包管理器,想用哪个框架,加个配置文件、不用把配置删掉就可以了,本篇文章要使用到的依赖如下
<!--MySQL的驱动-->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>5.1.29</version>        </dependency>        <!--Mybatis依赖-->        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>3.3.0</version>        </dependency>        <!--添加hibernate的核心依赖-->        <dependency>            <groupId>org.hibernate</groupId>            <artifactId>hibernate-core</artifactId>            <version>5.0.12.Final</version>        </dependency>添加完依赖后需要加载依赖,进入 pom.xml 文件  右击 -> Maven->重新加载项目,但是有些依赖本地没有下载,这个时候就需要添加远程仓库,加载远程仓库的资源。
编辑
Maven远程仓库配置   在项目中打开Pom.xml文件 右击页面  Maven ->打开 settings.xml
编辑
添加以下代码,这里加载的是阿里云公共仓库
<?xml version="1.0" encoding="UTF-8"?><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">    <mirrors>        <mirror>            <id>aliyunmaven</id>            <mirrorOf>*</mirrorOf>            <name>阿里云公共仓库</name>            <url>https://maven.aliyun.com/repository/public</url>        </mirror>    </mirrors></settings>​​第三章、JDBC 拼接注入
描述:Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC有两种方法执行SQL语句,分别为statement、PreparedStatement,statement语句存在拼接注入的问题,PreparedStatement使用占位符的方式 对参数的内容进行了过滤。
环境搭建
1、创建一个jdbc-Servlet,右击  com.hacker.servlet ->新建->servlet
编辑
2、修改下 @WebServlet 注解   value值修改为jdbc 方便访问,  将doGet()方法修改如下  注意 dburl 字符串 用于连接数据库,其中 demo 为数据库名,useSSL=false 是用于消除警告。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {try {//设置输出格式,防止乱码response.setContentType("text/html;charset=utf-8")rintWriter out =response.getWriter();//获取cid参数的值String cid=request.getParameter("cid");//固定格式 连接数据库 demo Class.forName("com.mysql.jdbc.Driver");String dburl = "jdbc:mysql://127.0.0.1:3306/demo?"+"user=root&password=admin@123&useSSL=false";Connection conn = DriverManager.getConnection(dburl);//使用 statement 方法执行sql语句  (存在注入)String sql1="select *from shops where cid="+cid;Statement statement = (Statement) conn.createStatement();ResultSet st= statement.executeQuery(sql1);out.println("<h2>使用statement()方法</h2>");out.println("<h3>"+sql1+"</h3>");while (st.next()){out.print("<h3>"+st.getObject(2)+"</h3>");System.out.println(st.getObject(2));}out.print("-------------------------------");System.out.println("----------------------");//使用PreparedStatement  预处理方法,防止sql注入String sql2="select *from shops where cid=?"reparedStatement pt=conn.prepareStatement(sql2);pt.setString(1,cid);ResultSet rt2= pt.executeQuery();out.println("<h2>使用PreparedStatement()方法</h2>");while (rt2.next()){out.println("<h3>"+rt2.getObject(2)+"</h3>");out.println("<h3>"+pt+"</h3>");}} catch (Exception e) {e.printStackTrace();}}3、访问url http://localhost:8080/jdbc?cid=2-1, 可以看到 使用Statement 执行sql语句 存在注入。
编辑

第四章、Mybatis框架注入描述:MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
Mybatis是SSM(Sprint+Struts2+Mybatis)框架中的一员,用于数据库连接、数据处理。Mybatis的特性是将sql语句写在配置文件中,接口类与配置文件进行绑定,使用动态代理的方式,完成接口函数的实现,返回数据。
环境

1、在pom.xml文件  <plugins>目录下  添加Free MyBatis plugin插件 配置
<!-- mybatis generator 自动生成代码插件 -->            <plugin>                <groupId>org.mybatis.generator</groupId>                <artifactId>mybatis-generator-maven-plugin</artifactId>                <version>1.3.5</version>                <configuration>                    <!--配置文件的位置-->                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>                    <overwrite>true</overwrite>                    <verbose>true</verbose>                </configuration>            </plugin>2、在resoult目录下创建generatorConfig.xml 并添加以下配置
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration>    <!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包找不到的话去下载一个-->    <classPathEntry  location="D:\Users\Zzz\IdeaProjects\demo-web04\web-demo06\src\main\resources\mysql-connector-java-5.1.45-bin.jar"/>    <context id="DB2Tables"  targetRuntime="MyBatis3">        <commentGenerator>            <property name="suppressDate" value="true"/>            <!-- 是否去除自动生成的注释 true:是 :false:否 -->            <property name="suppressAllComments" value="true"/>        </commentGenerator>        <!--数据库链接URL,用户名、密码 -->        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1/demo" userId="root" password="admin@123">        </jdbcConnection>        <javaTypeResolver>            <property name="forceBigDecimals" value="false"/>        </javaTypeResolver>        <!-- 生成模型的包名和位置-->        <javaModelGenerator targetPackage="com.hacker.mybatis" targetProject="src/main/java">            <property name="enableSubPackages" value="true"/>            <property name="trimStrings" value="true"/>        </javaModelGenerator>        <!-- 生成映射文件的包名和位置-->        <sqlMapGenerator targetPackage="main.resources.mapping" targetProject="src">            <!-- enableSubPackages:是否让schema作为包的后缀 -->            <property name="enableSubPackages" value="false" />        </sqlMapGenerator>        <!-- 生成DAO的包名和位置-->        <javaClientGenerator type="XMLMAPPER"  targetPackage="com.hacker.mybatis" targetProject="src/main/java">            <property name="enableSubPackages" value="true"/>        </javaClientGenerator>        <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->        <table tableName="shops"               domainObjectName="shops"               enableCountByExample="false"               enableUpdateByExample="false"               enableDeleteByExample="false"               enableSelectByExample="false"               selectByExampleQueryId="false">        </table>    </context></generatorConfiguration>3、使用插件生成mybatis框架所需的文件
​​
编辑
4、生成了以下3个文件
编辑
1)、shops   javaBean对象 与表结构对应,用于接收或查询数据,一张表对应一个JavaBean对象
2)、shopsMapping  一个接口类,使用动态代理的方式执行  result/mapping/shopMapping.xml 中编写好的sql语句,<select>、<update>、<delete>标签中ID属性与接口的名字相对应
3)、shopMapper.xml  ,用于编写Sql语句,需要被配置到mybatis-config.xml文件中,之前并没有创建,接下来需要创建一个mybatis-config.xml文件。

5、在resource 目录下创建mybatis-config.xml文件,并添加以下配置,将shopMapper.xml添加至Mapping标签。
<?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>    <settings>        <setting name="logImpl" value="STDOUT_LOGGING" />    </settings>    <environments default="dev">        <environment id="dev">            <transactionManager type="JDBC"></transactionManager>            <dataSource type="UNPOOLED">                <property name="url" value="jdbc:mysql://localhost:3306/demo"/>                <property name="driver" value="com.mysql.jdbc.Driver"/>                <property name="username" value="root"/>                <property name="password" value="admin@123"/>            </dataSource>        </environment>    </environments>    <mappers>        <mapper resource="mapping/shopsMapper.xml"/>    </mappers></configuration>6、接下来创建一个Servlet,在doGet()方法中编写核心代码 ,在以下代码中,加载了shopsMapping 类,并调用了findById1()   ,findById2()
response.setContentType("text/html;charset=utf-8");        PrintWriter out =response.getWriter();        out.println("<h1>Hello</h1>");        String cid=request.getParameter("cid");        //定义读取文件名        String resources = "mybatis-config.xml";        //创建流        Reader reader=null;        try {            //读取mybatis-config.xml文件到reader对象中            reader= Resources.getResourceAsReader(resources);        } catch (IOException e) {            e.printStackTrace();        }        //初始化mybatis,创建SqlSessionFactory类的实例        SqlSessionFactory sqlMapper=new SqlSessionFactoryBuilder().build(reader);        //创建session实例        SqlSession session=sqlMapper.openSession();        shopsMapper s=session.getMapper(shopsMapper.class);        shops s1=s.findById(cid);        out.println("<h3>This is findById </h3>");        out.println(s1.getCname());        out.print("<h2>--------------------------------</h2>");        System.out.println("-------------------------------------------");        shops s2=s.findById2(cid);        out.println("<h3>This is findById2</h3>");        out.println(s2.getCname());7、重写shopsMapping接口类,并添加 findById1(),findById2() 方法
public interface shopsMapper {    shops findById(String id);    shops findById2(@Param(value = "id") String id);}8、重写  resources/mapping/shopsMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.hacker.mybatis.shopsMapper">  <select id="findById" parameterType="string" resultType="com.hacker.mybatis.shops">    select * from shops where cid = #{id}  </select>  <select id="findById2" parameterType="string" resultType="com.hacker.mybatis.shops">    select * from shops where cid = ${id}  </select></mapper>9、运行项目,输入 http://localhost:8080/mybatisServlet?cid=2-1
​​
编辑

编辑
第五章、Hibernate 框架注入描述:Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库,通常与 Sprint+SprintMVC框架搭配使用。

环境搭建:
1、利用IDEA插件,生成hibernate.fig.xml配置文件, 文件->结构项目->模块->添加 hibernate 模块
编辑
编辑
2、连接数据源
编辑
3、生成配置文件,persistence比较难找,直接使用视图的功能
编辑
4、生成对象映射关系,生成了 shopEntity 类、/resource/shopEntity.hbm.xml
​​
编辑
编辑
5、创建一个hibernateServlet类,在doGet()方法中添加以下核心代码
response.setContentType("text/html;charset=utf-8");        PrintWriter out =response.getWriter();        out.println("<h1>This is Hibernate_sql_Servlet</h1>");        String cid=request.getParameter("cid");        Configuration conf = new Configuration().configure();        SessionFactory sessionFactory = conf.buildSessionFactory();        Session session = sessionFactory.openSession();        Transaction tx = session.beginTransaction();        ShopsEntity shop= session.get(ShopsEntity.class,1);        String sql="from com.hacker.hibernate.ShopsEntity where cid=:cid ";        Query query=session.createQuery(sql).setString("cid",cid);        String cname=((ShopsEntity)query.list().get(0)).getCname();        System.out.println(cname);        out.println("<h2>"+cname+"</h2>"+"<h2>"+sql+"</h2>");        System.out.println("-----------------------------------------------------");        out.println("<h2>----------------------------------------------------<h2>");        String sql2="from com.hacker.hibernate.ShopsEntity where cid="+cid;        Query query2=session.createQuery(sql2);        String cname2=((ShopsEntity)query2.list().get(0)).getCname();        out.println("<h2>"+cname2+"</h2>");        System.out.println(cname2);          tx.commit();       session.close();6、输入 http://localhost:8080/hibernate?cid=2-1
编辑


总结:在学习java代码审计之前应先熟悉javaWeb基础知识,了解框架的特性,不要求能够编写代码,但至少能够看懂程序是如何跑起来的,项目代码已上传至 github  https://github.com/Zzz98k/java_sql_demo,供大家参考学习,不足之处还请各位师傅多多指点。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-19 22:24 , Processed in 0.016783 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表