Java代码审计-sql注入基础篇
2022-9-28 09:10:26 Author: 编码安全研究(查看原文) 阅读量:20 收藏

目录:
一、javaWeb的项目搭建二、Maven介绍三、JDBC 拼接注入四、Mybatis框架注入五、Hibernate 框架注入

简介:

本篇文件的标题虽然是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");PrintWriter 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&[email protected]&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=?";PreparedStatement 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="[email protected]"> </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="[email protected]"/> </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,供大家参考学习,不足之处还请各位师傅多多指点。

注:如有侵权请联系删除

   学习更多技术,关注我:   

觉得文章不错给点个‘再看’吧

文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDY1MDc2Mg==&mid=2247496180&idx=1&sn=d27e02fb0ac90cfab9fece315a0aba44&chksm=ce64a291f9132b8793f14cd54c54103a23a1ef1e41c6e2eb6ec5c44ea7f81a3673a35afc07b1#rd
如有侵权请联系:admin#unsafe.sh