Spring审计入门

Java spring审计

spring的一些概念

JavaBean

JavaBean 是一种JAVA语言写成的可重用组件。与POJO(Plain Ordinary Java Object)不同,JavaBean是符合一定规范编写的Java类,不是一种技术,而是一种规范。大家针对这种规范,总结了很多开发技巧、工具函数。符合这种规范的类,可以被其它的程序员或者框架使用。它的方法命名,构造及行为必须符合特定的约定:

  • 所有属性为private。

  • 这个类必须有一个公共的缺省构造函数。即是提供无参数的构造器。

  • 这个类的属性使用getter和setter来访问,其他方法遵从标准命名规范。

  • 这个类应是可序列化的。实现serializable接口。

因为这些要求主要是靠约定而不是靠实现接口,所以许多开发者把JavaBean看作遵从特定命名约定的POJO

spring处理请求的流程

通过DispatcherServlet 这个前置拦截器类来拦截请求通过映射将请求分发给各控制器处理,最后通过org.springframework.web.servlet.view.InternalResourceViewResolver视图解析器返回响应页面
流程图倒是有,避免抄袭就不直接搬运了,可以从这里看
参考链接1
参考链接2

IOC、依赖注入

IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

举个例子,一个杂货铺(C类),要卖鸡蛋(A类)和鸭蛋(B类),那他需要先进鸡蛋和鸭蛋,在有了鸡蛋和鸭蛋之后再输出货物。而IOC容器就像这个杂货铺背后的连锁总店,在连锁杂货铺开张的时候,杂货铺就在连锁总店中定义了我要卖鸡蛋和鸭蛋,然后当订单来到时,杂货铺不需要自己去购进鸡蛋和鸭蛋,而是连锁总店得知店开张了自动把鸡蛋和鸭蛋送过来给杂货铺。对于杂货铺C类和来源的关系来说,一个是pull,一个是push。

这种方式不需要再每个调用C类对象的时候再额外声明创建一个A类一个B类并放到C成员对象中去。
依赖注入也就是IOC的应用,当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了

依赖注入方式

setter注入

package com.class.springdemo.action;  
public class SpringAction {   
    private SpringDao springDao;  
        public void setSpringDao(SpringDao springDao) {  
        this.springDao = springDao;  
    }  
  
        public void ok(){  
        springDao.ok();  
    }  
}  

配置xml写法:

<bean name="springAction" class="com.class.springdemo.action.SpringAction">   
        <property name="springDao" ref="springDao"></property>  
    </bean>  
<bean name="springDao" class="com.class.springdemo.dao.impl.SpringDaoImpl"></bean>  

构造器注入

public class SpringAction {  
    //注入对象springDao  
    private SpringDao springDao;  
    private User user;  
      
    public SpringAction(SpringDao springDao,User user){  
        this.springDao = springDao;  
        this.user = user;  
        System.out.println("success");  
    }  
          
        public void save(){  
        user.setName("kkkkkk");  
        springDao.save(user);  
    }  
}  
    <bean name="springAction" class="com.class.springdemo.action.SpringAction">  
        <constructor-arg ref="springDao"></constructor-arg>  
        <constructor-arg ref="user"></constructor-arg>  
    </bean>  
        <bean name="springDao" class="com.class.springdemo.dao.impl.SpringDaoImpl"></bean>  
         <bean name="user" class="com.class.springdemo.vo.User"></bean> 

注解
自动装配
会根据<context:component-scan base-package="test"/>自动扫描组件目录

@Autowired是spring的注解,默认使用的是优先byType后byName的方式向Bean里面注入相应的Bean。例如:

@Autowired
private UserService userService;

这段代码会在初始化的时候,在spring容器中寻找一个类型为UserService的bean实体注入,关联到userService的引入上

byName

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" 
          > 
  <bean name="userDAO" class="com.sc.dao.impl.UserDAOImpl"> 
   <property name="daoId" value="1"></property> 
  </bean> 
  
  <bean name="userDAO2" class="com.sc.dao.impl.UserDAOImpl"> 
   <property name="daoId" value="2"></property> 
  </bean> 

  <bean id="userService" class="com.sc.service.UserService"  autowire="byName"><!-- 这里的byName是按照属性名进行匹配 这里我们并没有配置注入UserDAO 但是你的UserService属性名称是UserDAO 所以就相当于 你注入了UserDAO--> 
相当于这样  <property name="userDAO" ref="userDAO"/> 

byType处理机制类似

AOP

面向切面编程,对所有业务流程的同一节点切面进行附加业务代码的一种方式
---|A|-------程序1流程--
---|O|-------程序2流程--
---|P|--------程序3流程--
----\ /---------程序4流程--
分类
前置通知(do something point)
后置通知(point do something)
环绕通知(do something point do something)
声明方式如下

切入点配置

匹配绑定
非事务AOP声明代码类似:

<aop:config>
            <aop:aspect id="time" ref="timeHandler">
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
        </aop:config>

Filter

对径直进入程序流程的部分进行添加附加业务代码的一种方式
--------=====------程序1流程----->
--------|filter|------程序1流程-------->
--------=====------程序1流程----->

filter配置方式,一眼可见配置项是什么意思

<filter>
        <filter-name>xssCheckFilter</filter-name>
        <filter-class>cn.test.common.web.XSSCheckFilter</filter-class>
    </filter>
   <filter-mapping>
        <filter-name>xssCheckFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>xssCheckFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>XssFilter</filter-name>
        <filter-class>cn.test.common.web.XssFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>XssFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>XssFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>

filter代码

public class XSSCheckFilter implements Filter {
..........
public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain filterChain) throws ServletException {
                .........//A部分
                filterChain.doFilter(req, res);
                ........//B部分
            }
    public void destroy() {
......}

执行优先级
在web.xml中,filter执行顺序跟<filter-mapping>的顺序有关,先声明的先执行
使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter
filter chain
根据定义的filter配置,可能存在多次捕获进入filter的情况——filter链。根据顺序执行filter,例如xsscheckfilter和authfilter一同作用,xss先,auth后,则先执行xss的A部分代码,执行auth的A部分代码,auth的B部分,xss的B部分。

Datasource

数据源配置,一般用porperties文件存放信息

事务

advice(配置事务)、advisor(配置事务和切点的匹配)。对某个操作函数通过注解或者配置声明为它赋予事务属性

如何下手审计代码(审计入手点)

找到各配置文件位置、查看大概配置内容

WEB-INF/web.xml 一般用于配置监听器处理映射、配置全局Filter、服务器配置定义(如错误信息等)
映射查看 通过查看监听器的内容、url pattern的设置、额外xml文件的引入、requestmapping注解查看对应控制器,例如:

监听器配置
至于对应context的引入则需要查看引入的xml文件了,不管是通过注解还是setter、构造器注入,都会有对应Bean的声明

Controller层

简单数据传递的前端控制器层,逻辑较少,容易出现前端注入类漏洞,如XSS、前端代码注入、任意跳转等;审计过程和PHP代码审计差不多,需要注意的是可控参数的限制可能会在接口里、filter或aop里、入参类型限制,单纯在调用上如果找不到限制认为就存在漏洞可能会有问题。

Service层

主要是具体逻辑业务接口实现,涉及具体逻辑编写,数据操作,容易出现逻辑漏洞或影响后端的漏洞,如任意文件
上传/下载、XML注入、SQL注入等;危险函数的查找大部分是在接口的实现中进行查看,当然还是主要靠ctrl+shift+F 。
PS:这里可以深刻的感受到面向接口编程

DAO层

SQL接口的实现,比较底层,自己用jdbc实现的话小可能会有由逻辑问题带来的SQL注入漏洞,如正确使用jdbctemplate、Mybatis 或 hibernate 的$和#则不会存在此类问题。

顺序

从web.xml入手,查看映射怎么配置的,有什么filter,aop啥的,然后根据配置看其他地方的额外的xml配置,大概摸清楚入口和映射。

根据前端控制器,追可控点,追进service层看底下代码怎么写的有没有用危险函数,但此方法工作量大;或者通过搜索危险函数追参数调用,不过从危险函数开始追的话因为引用库比较多,可能会有遗漏。

最好黑白盒结合通过业务功能来进行判断。

dao如果是用的框架一般最后去看,正确使用$ #的话就不看了,查看有没有类似order by这种可控点会不会有问题

Spring Boot

接触的不多,感觉是更加简单的引入外部库、前后端和启动web相关的各种配置,其他差别不大

结合maven,内置tomcat

后续

感觉看多了spring的java代码,再反过来看java反序列化的说明,以前是觉得每个字都认识,就是看不大懂,现在至少可以看懂文章写得原理了。或许在之后会去学习一下框架的代码审计和漏洞挖掘。

目前看来可能代码审计做得还是比较少,感觉能看懂,但是一些审计的技巧,那种老流氓式的快速翻一翻就能找到问题的姿势还没找到。
如有问题欢迎指正


发表评论 暂无评论

*