从1开始的Java代码审计·第二弹·基础篇(下)

我们在审计一个项目的时候,最开始应该是先熟悉项目的结构,了解项目的技术栈。

本篇,我会引入一个开源的 Java Web 项目,通过实例分析 Java Web 的项目结构,常用的 MVC 模式。

JEESNS

JEESNS,是一款基于 JAVA 企业级平台研发的社交管理系统,在 github 上有 200+ star,在开源的 Java Web 项目中算是还不错的了。在本章及后面的内容,我会用它做实例,进行审计分析。

项目地址: https://github.com/zchuanzhao/jeesns

下载项目

你可以直接把项目 clone 下来,然后导入到 IDE。也可以直接在 IDEA 里把项目从 VCS(版本控制系统)中 checkout 出来。

下面我演示下,如何在 IDEA 里直接从 git 服务器上迁出项目。

  1. 打开 IDEA,点Check out from Version Control,选择Git
    check1

  2. 在弹出的 dialog 里,输入 git 的地址(https://github.com/zchuanzhao/jeesns.git),以及本地保存的位置,然后`clone`。
    check2

  3. 之后,IDEA 会开始下载项目,并构建,下面是构建完毕的项目工程。
    check3


项目结构解析

Maven

根目录下的 pom.xml

在项目的根目录下,有一个pom.xml的文件,这个文件的存在,表明项目是用Maven构建的,关于 Maven 可以点这里。它是用来管理项目源码、配置文件,不过最大的用处还是处理项目的依赖关系。作用有点类似于 nodejs 的 npm,python 的 pip。

下面,点开这个pom.xml

maven1

红框的 ① 处,描述了这个项目的开发组织,项目名称,项目版本。

② 处,用的是modules标签,说明这是一个多模块项目。在左边的导航栏,可以看到确实有许多子模块。

多模块项目是为了在项目开发中便于后期维护,所以采用分层开发的方法,这样各个模块的职责会比较的明确,维护起来相对容易。在打包时,只要对父模块打包即可,子模块会自动合并进来。

③ 处,是 maven 在构建时相关的配置,这里用了一个 compiler 插件,表示源码用的是1.7JDK并且生成的目标字节码文件也要是1.7的。

子模块下的 pom.xml

点开每个子模块,看到每个模块下还会有一个pom.xml

maven2

随便点一个pom.xml,它和根目录下的pom.xml有所不同,多了一个<parent>标签,和dependencies

<parent>标签,表示这个子模块,将上级的jeesns项目作父模块。

dependencies,描述了这个模块的依赖关系。当前的web模块依赖于子模块core,model,service,common。而子模块core里,依赖于许多的第三方库,包括SpringMyBatisapache-commons等。它们都继承了上级的jeesns父模块,在逻辑上同属一个项目。

相关文章 https://www.cnblogs.com/davenkin/p/advanced-maven-multi-module-vs-inheritance.html

第三方库的安全检查

前面有说过,pom.xml有个重要的作用是管理依赖关系。在<dependencies>中填写要引入的第三方库信息,Mavenimport时,会从仓库下载相关的库文件,加入到当前项目。

我们需要<dependencies>中,检查使用的第三方库是否有已知的安全漏洞。
这里只要根据组件名称、版本号,去官网或者CVE漏洞库搜下就行了。如果项目很大,引入了太多库,这也是件很累的事情。

所以 OWASP 出了一个工具 Dependency_Check 专门检查这类问题,这个工具的使用在前面一篇已经讲过了,就不多介绍了。

子模块

JEESNS 一共分了六个子模块,分别是 jeesns-commonjeesns-corejeesns-daojeesns-modeljeesns-servicejeesns-web

接下来,我们来分析各个子模块的作用。

jeesns-core

看名字就知道,这是这套 Web 程序的核心部分。

通过分析 pom.xml 文件,发现它引入了以下第三方库:

库名 用途
spring-* spring 框架相关
freemarker 前端模板引擎
httpclient http 客户端
mysql-connector mysql 连接器驱动
c3p0 数据库连接池
mybatis 半自动 ORM 框架
hibernate-validator 数据有效性验证
jackson json 数据处理库
jsoup html 解析器
log4j 日志管理框架
commons-io io 工具类
commons-codec 编码处理工具类
commons-lang Java 基本对象工具类
commons-fileupload 提供文件上传功能
commons-logging 提供 Java 日志接口

根据上表,即使我们不看官方的介绍,也基本可以确定这套程序的技术栈。

主要使用了 SSM框架 (Spring+SpringMVC+MyBatis), freemarker 模板引擎,支持 MySQL 数据库,使用 c3p0 连接池,jackson 处理 json 数据,hibernate-validator 对用户传来的请求数据进行有效性验证,还有一些 apache 提供的工具类。

包结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- core

- annotation 定义注解

- consts 定义常量

- directive 定义了一个抽象类 `BaseDirective` ,所有的标签类都会继承它

- dto 定义`响应结果`的数据传输模型

- enums 定义功能相关的常量

- exception 定义异常

- filter 定义过滤器,目前只有一个`XSS`过滤器

- handler 定义处理器,目前只有`DirectiveHandler`,负责处理每个页面的渲染

- model 定义了数据模型,这里只有`Page`,描述页面对象,用于数据分页情况

- utils 定义工具类

+ interceptor

- PageInterceptor 分页拦截器,处理需要分页的请求。

模块小结

通过分析 jeesns-core 的模块,我们已经知道了 jeesns 的技术栈,是目前比较流行的 SSM 框架,这个核心模块给整个项目构建了一个基本骨架,包括功能方面的还有我们关心的安全方面的(虽然只有 XSS 防御 ($ _ $) )。

在分析下面模块之前,我们需要先了解 SSM 的一些概念。参考文章

当然,最重要的还是要知道什么是 MVC,因为大部分的 Web 项目,都是基于这种设计模式开发的,包括 JEESNS参考文章

设计模式与编程语言无关,可以说是一套经验科学,由前人总结、分类,被广泛使用。目的是为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。

Java 设计模式学习链接:https://github.com/AlfredTheBest/Design-Pattern

如果,你已经了解了SSMMVC的概念,那就接着往下看吧 O(∩_∩)O

jeesns-web

对应 MVC 中的 Controller 层,负责具体业务的模块流程的控制,会调用到下面 Service 层的接口来控制业务流程。

webapp 里是 View 层用到的静态资源(js、css、jpg)以及freemarker的模板文件。

resources 里,有项目相关的各种配置文件。

模块小结

Controller 层和 View 层结合的最紧密,两者通常协同开发。

这里的 Controller 层还设置了监听器,负责对用户的身份和权限进行认证管理。

通常在 Java Web 里,我们会用 Spring-SecurityShiro 这些第三方库来帮助我们实现用户认证和用户授权的功能 。

jeesns-service

Service 层,主要负责业务模块的应用逻辑应用设计,先设计接口,在设计实现类。这一层,是纯业务逻辑。在使用 Service 层时,会继续调用下面的 DAO 层的接口。

jeesns-dao

DAO 层,负责数据持久化,通俗点说就是用来和数据库交互,读写数据的模块。

前面有说到,JEESNS 用了 MyBatis 作为数据持久化框架。MyBatis 属于半自动 ORM ,它会帮我们自动将数据查询结果映射到对象,但是数据查询的 SQL 语句还是要我们自己手写,这点和其它的 ORM 明显的不一样。

MyBatis 的使用方式主要有两种,一种是使用注解,直接将SQL语句和方法绑定在一起,像下面这样:

1
2
3
4
5
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}

这种方式,适合简单的SQL语句,一旦语句长了,注释会变得复杂混乱,维护起来很麻烦,所以它只适合小项目(小项目用的也不多)。

用的最多的是第二种——XML配置,将SQL语句和Java代码分离,有独立的xml文件,描述某个方法会和某个SQL语句绑定。

mybatis1

如图,每一个接口,在资源文件目录中,都有对应的xml。接口中的方法,和xmlid相同的SQL语句关联。

例如,IArticleCateDaolist()方法被调用,那么就会找到 ArticleCateMapper.xmlid等于 list 的方法,执行它的 SQL,然后根据 resultMap 描述的 字段-属性 映射关系,返回相应的实例对象。

这里的 resultMap 具体如下:

1
2
3
4
5
6
7
<resultMap id="ArticleCateResult" type="ArticleCate">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="fid" jdbcType="INTEGER" property="fid" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="status" jdbcType="INTEGER" property="status" />
<result column="sort" jdbcType="INTEGER" property="sort" />
</resultMap>

其中,id属性是该映射的名称,type属性代表映射的类。里面有 5 个子元素,id元素映射到ArticleCateid属性。其它四个result元素中的column属性会映射到对应的property属性。

模块小结

dao 模块负责数据的持久化,会和数据库交互。开发者编写的SQL语句也定义在这个模块,MyBatis有特殊的语法将查询的参数代入到SQL语句中,如果开发者在这里使用的语法有问题,就有极有可能出现 SQL注入

jeesns-model

定义了所有和功能业务相关的数据模型,和数据库表对应。

jeesns-common

定义了其它模块会用到的常量以及工具类。

总结

本篇主要以 JEESNS 为例,介绍了目前比较流行的 Java Web 项目的结构。

理清项目结构后,我们就可以继续下一步——漏洞挖掘啦。

文章目录
  1. 1. JEESNS
    1. 1.1. 下载项目
  2. 2. 项目结构解析
    1. 2.1. Maven
      1. 2.1.1. 根目录下的 pom.xml
      2. 2.1.2. 子模块下的 pom.xml
    2. 2.2. 第三方库的安全检查
    3. 2.3. 子模块
      1. 2.3.1. jeesns-core
        1. 2.3.1.1. 包结构
        2. 2.3.1.2. 模块小结
      2. 2.3.2. jeesns-web
        1. 2.3.2.1. 模块小结
      3. 2.3.3. jeesns-service
      4. 2.3.4. jeesns-dao
        1. 2.3.4.1. 模块小结
      5. 2.3.5. jeesns-model
      6. 2.3.6. jeesns-common
  3. 3. 总结
|