Javaweb安全——Java类加载机制
前言
参照https://javasec.org/以及p神的Java安全漫谈的路线进行学习,类似读书笔记那种吧。之前都是ctf遇到Java的题才学一点,像是反序列化这种,没系统化的学过Java Web安全,这次从头来好好学一遍。
Java平台版本
Java平台共分为三个主要版本Java SE
(Java Platform, Standard Edition
-Java平台标准版)、Java EE
(Java Platform Enterprise Edition
-Java平台企业版)、和Java ME
(Java Platform, Micro Edition
-Java平台微型版)。Java SE
是JDK自带的标准API,是Java学习的基础。
ClassLoader(类加载机制)
Java是一个依赖于JVM
(Java虚拟机)实现的跨平台的开发语言。Java程序在运行前需要先编译成class文件
,Java类初始化的时候使用类加载器创建。
加载器分为两种:由 Java 虚拟机提供的引导类加载器,以及用户定义的类加载器。 每个用户定义的类加载器都是一个ClassLoader
抽象类的子类的实例.
Java类初始化的时候会调用java.lang.ClassLoader
加载类字节码,ClassLoader
会调用JVM的native方法(defineClass0/1/2
)来定义一个java.lang.Class
实例(创建一个对象)。
JVM架构图:
ClassLoader
一切的Java类都必须经过JVM加载后才能运行,而ClassLoader
的主要作用就是Java类文件.class 的加载。将 Class 的字节码形式转换成内存形式的 Class 对象。字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,字节码的本质就是一个字节数组 []byte,它有特定的复杂的内部格式。
.class文件结构示例
JVM类加载器内置了三个重要的类加载器,三者形成层次结构,从上到下依次为:
Bootstrap ClassLoader(引导类加载器,内嵌在java虚拟机中由C++编写)
主要加载核心类库,ClassLoader就是是由它来加载的,它并不是Java类,而其它加载器则都是Java类。Extension ClassLoader(扩展类加载器)
,负责加载 JVM 扩展类,比如 swing 系列、内置的 js 引擎、xml 解析器 等等,这些库名通常以 javax 开头,它们的 jar 包位于 JAVA_HOME/lib/ext/*.jar 中。Java9之后更名为platform classloaderApp ClassLoader(系统类加载器)
,AppClassLoader
会加载 Classpath 环境变量里定义的路径中的 jar 包和目录,是默认的类加载器,如果类加载时我们不指定类加载器的情况下,默认会使用AppClassLoader
加载类,ClassLoader.getSystemClassLoader()
返回的系统类加载器也是AppClassLoader
。
jdk还内置了一个 URLClassLoader,用户只需要传递规范的网络路径给构造器,就可以使用 URLClassLoader 来加载远程/本地类库,取决于构造器中不同的地址形式。ExtensionClassLoader 和 AppClassLoader 都是 URLClassLoader 的子类,它们都是从本地文件系统里加载类库。
这三个类加载器实例的父子关系如上图,不过虽然ExtClassLoader是AppClassLoader父加载器,但却是由Bootstrap加载的AppClassLoader
如同上图当中的例子所示,某些时候我们获取一个类的类加载器时,可能会返回一个null
值,如:java.io.File.class.getClassLoader()
将返回一个null
对象,因为java.io.File
类在JVM初始化的时候会被Bootstrap ClassLoader(引导类加载器)
加载(该类加载器实现于JVM层,采用C++编写),我们在尝试获取被Bootstrap ClassLoader
类加载器所加载的类的ClassLoader
时候都会返回null
。
还需注意的是上面所提到的父子加载器并不是类继承上的父子关系,是类加载器实例之间的关系。类继承关系如下图所示:
ClassLoader
类有如下核心方法:
loadClass
(加载指定的Java类)findClass
(查找指定的Java类)findLoadedClass
(查找JVM已经加载过的类)defineClass
(定义一个Java类)resolveClass
(链接指定的Java类)
Java类动态加载方式
Java类加载方式分为显式
和隐式
,显式
即我们通常使用Java反射
或者ClassLoader
来动态加载一个类对象,而隐式
指的是类名.方法名()
或new
类实例。显式
类加载方式也可以理解为类动态加载
,我们可以自定义类加载器去加载任意的类。
常用的类动态加载方式:
// 反射加载TestHelloWorld示例
Class.forName("HelloTest");// ClassLoader加载TestHelloWorld示例
this.getClass().getClassLoader().loadClass("HelloTest");
Class.forName("类名")
默认会初始化被加载类的静态属性和方法,如果不希望初始化类可以使用Class.forName("类名", 是否初始化类, 类加载器)
,而ClassLoader.loadClass
默认不会初始化类方法。Class.forName()
方法可以获取原生类型的 Class,而ClassLoader.loadClass()
则会报错。
如上图所示,必须等到Class.forName
执行才完成对Tester类的初始化。
ClassLoader类加载流程
先了解一下JVM的三种主要类加载机制:
缓存机制:
保证所有加载过的Class都会被缓存。即当需要某个类时会先从缓存区中搜寻该Class,若没有则进行加载。(修改Class后,必须重启JVM)
JVM判断两个类对象相同的两个条件:
- 类的完整名必须一致
- 加载这个类的ClassLoader实例必须为同一个
父类委托 /双亲委派:
某个特定的类加载器在接到加载类的请求时,首先判断这个class是否以及加载成功,如果没有则将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
委托机制的意义 — 防止内存中出现多份同样的字节码。
全盘负责:
当一个类加载器负责加载某个Class时,该Class所依赖的和引用的Class也将由其负责载入,除非显式指定另一加载器。
ClassLoader
加载Tester
类重要流程如下:
ClassLoader
会调用public Class<?> loadClass(String name)
方法加载Tester
类。- 调用
findLoadedClass
方法检查Tester
类是否已经初始化,如果JVM已初始化过该类则直接返回类对象。 - 如果创建当前
ClassLoader
时传入了父类加载器(new ClassLoader(父类加载器)
)就使用父类加载器加载Tester
类,否则使用JVM的Bootstrap ClassLoader
加载。 - 如果上一步无法加载
Tester
类,那么调用自身的findClass
方法尝试加载Tester
类。 - 如果当前的
ClassLoader
没有重写了findClass
方法,那么直接返回类加载失败异常。如果当前类重写了findClass
方法并通过传入的Tester
类名找到了对应的类字节码,那么应该调用defineClass
方法去JVM中注册该类。 - 如果调用loadClass的时候传入的
resolve
参数为true,那么还需要调用resolveClass
方法链接类,默认为false。 - 返回一个被JVM加载后的
java.lang.Class
类对象。
类加载隔离
创建类加载器的时候可以指定该类加载的父类加载器,ClassLoader是有隔离机制的,不同的ClassLoader可以加载相同的Class(两则必须是非继承关系),同级ClassLoader跨类加载器调用方法时必须使用反射。
BCEL ClassLoader
BCEL(
Apache Commons BCEL™
)是一个用于分析、创建和操纵Java类文件的工具库,Oracle
JDK引用了BCEL库,不过修改了原包名org.apache.bcel.util.ClassLoader
为com.sun.org.apache.bcel.internal.util.ClassLoader
,BCEL的类加载器在解析类名时会对ClassName中有$$BCEL$$
标识的类做特殊处理,该特性经常被用于编写各类攻击Payload。BCEL攻击原理
当BCEL的
com.sun.org.apache.bcel.internal.util.ClassLoader#loadClass
加载一个类名中带有$$BCEL$$
的类时会截取出$$BCEL$$
后面的字符串,然后使用com.sun.org.apache.bcel.internal.classfile.Utility#decode
将字符串解析成类字节码(带有攻击代码的恶意类),最后会调用defineClass
注册解码后的类,一旦该类被加载就会触发类中的恶意代码,正是因为BCEL有了这个特性,才得以被广泛的应用于各类攻击Payload中。示例 - BCEL类名解码:
BCEL编解码
BCEL编码:
byte[]{类字节码byte数组}];// BCEL编码类字节码 String className = "$$BCEL$$" + com.sun.org.apache.bcel.internal.classfile.Utility.encode(CLASS_BYTES, true); ```编码后的类名:`$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85S$dbn$d......`,BCEL会对类字节码进行编码,**BCEL解码:**```java int index = className.indexOf("$$BCEL$$"); String realName = className.substring(index + 8);// BCEL解码类字节码 byte[] bytes = com.sun.org.apache.bcel.internal.classfile.Utility.decode(realName, true); ```如果被加载的类名中包含了`$$BCEL$$`关键字,BCEL就会使用特殊的方式进行解码并加载解码之后的类。## ClassLoader总结`ClassLoader`是JVM中一个非常重要的组成部分,`ClassLoader`可以为我们加载任意的java类(配合反射机制实现,使得Java这一静态语言具有一定的动态性),通过自定义`ClassLoader`更能够实现自定义类加载行为。码类字节码 byte[] bytes = com.sun.org.apache.bcel.internal.classfile.Utility.decode(realName, true); ```如果被加载的类名中包含了`$$BCEL$$`关键字,BCEL就会使用特殊的方式进行解码并加载解码之后的类。
ClassLoader总结
ClassLoader
是JVM中一个非常重要的组成部分,ClassLoader
可以为我们加载任意的java类(配合反射机制实现,使得Java这一静态语言具有一定的动态性),通过自定义ClassLoader
更能够实现自定义类加载行为。
Javaweb安全——Java类加载机制相关推荐
- 两道面试题,带你解析Java类加载机制
2019独角兽企业重金招聘Python工程师标准>>> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Grandpa {static ...
- Java类加载机制详解【java面试题】
Java类加载机制详解[java面试题] (1)问题分析: Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数 ...
- 谈谈 Java 类加载机制
点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 来源:Rainstorm , github.com/c-rainstorm/blog/blob/m ...
- Java类加载机制:双亲委托模型
Java类加载机制:双亲委托模型 前言(废话) 一如既往,这篇博客是我极为浅显的理解,仅仅是我记录我自己成长的一环而已.我以前听我老师说过,什么是进步,进步就是当你三个月后重新再看自己的代码,发现那就 ...
- 深入研究Java类加载机制
深入研究Java类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载 ...
- Java类加载机制深度分析
为什么80%的码农都做不了架构师?>>> Java类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. ...
- Java高级篇——深入浅出Java类加载机制
转载自 Java高级篇--深入浅出Java类加载机制 类加载器 简单讲,类加载器ClassLoader的功能就是负责将class文件加载到jvm内存. 类加载器分类 从虚拟机层面讲分为两大类型的类加载 ...
- Java类加载机制的理解
算上大学,尽管接触Java已经有4年时间并对基本的API算得上熟练应用,但是依旧觉得自己对于Java的特性依然是一知半解.要成为优秀的Java开发人员,需要深入了解Java平台的工作方式,其中类加载机 ...
- java 加载类java_深入研究Java类加载机制
深入研究Java类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比 ...
- java版如何使区块常加载,Java类加载机制 - suer27zhu的个人空间 - OSCHINA - 中文开源技术交流社区...
首先上图 如图所示,Java类加载机制的六个阶段 Java代码编译完成后会生成对应的class文件,接着我们运行java命令的时候,其实是启动了JVM虚拟机执行class字节码文件的内容.大致分为六个 ...
最新文章
- 循环获取结构体中的健名与值的实现
- cmd打开java文件夹_Java用CMD打开指定文件和文件夹
- 将四个整数进行从小到大的顺序排列 java_07_Java基础语法_第7天(练习)_讲义(练习加强+在eclipse中实现)...
- ❤️六W字《计算机基础知识》(八)(建议收藏)❤️
- CTF:攻防世界web PART01
- Activiti6.0.0及以上版本集成Activiti Modeler
- 【Unity3D基础2-11】Unity3D网格和材质
- 栈的push,pop序列
- 【npm i 报错解决方法】npm ERR! code ERESOLVEnpm ERR!npm ERR! While resolving: by-web@1.2.2npm ERR!
- 淘宝店铺动销率对店铺有什么影响,怎样提高店铺动销率
- OSPF状态切换以及包内容的交互,以及如何根据LSDB还原单区域拓扑
- 【JavaLearn】 # (2)类和对象、变量、构造方法、普通方法、this关键字
- 【转】.NET引用Excel操作时无法关闭Excel.exe进程的解决方法
- PPT形状的多种玩法
- 【魏先生搞定Python系列】一文搞定Cufflinks画图
- hook createmutex openmutex 实现多开
- linux下查看磁盘空间
- 怎样看 计算机类b0809,计算机类(B0809、A0812、A0854)为什么是神?
- 基于springboot的毕业设计管理系统
- linux电池充电阀值控制