Java序列化反序列化原理及漏洞解决方案

 更新时间:2020年08月04日 15:49:26   作者:大专栏  
这篇文章主要介绍了Java序列化反序列化原理及漏洞解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

Java序列化

Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。

Java反序列化

反序列化就是将字节序列恢复为Java对象的过程

整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象,因此可以实现多平台之间的通信、对象持久化存储,主要有如下几个应用场景。

HTTP:多平台之间的通信,管理等

RMI:是 Java 的一组拥护开发分布式应用程序的 API,实现了不同操作系统之间程序的方法调用。值得注意的是,RMI 的传输 100% 基于反序列化,Java RMI 的默认端口是1099端口。

JMX:JMX 是一套标准的代理和服务,用户可以在任何 Java 应用程序中使用这些代理和服务实现管理,中间件软件 WebLogic 的管理页面就是基于 JMX 开发的,而 JBoss 则整个系统都基于 JMX 构架。

系列化反序列化基础

序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。

一个类的对象能够序列化的成功需要两个条件

  • 该类必须实现 java.io.Serializable 接口
  • 该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。

漏洞基本原理

简单的反序列化Demo

首先定义对象类Persion,包含两个参数

public class implements java.io.Serializable{
  public String name;
  public int age;
  public void info(){
    System.out.println("Name:"+this.name+";nAge:"+this.age);
  }
}

在主类中声明对象,并且将对象序列化为二进制文件,将其存储到硬盘中

import java.io.*;

public class Main{
  public static void main(String [] args){
    将对象序列化为二进制文件
    Persion p = new Persion();
    p.name = "Joner";
    p.age = 18;
    try {

      //打开一个文件输入流
      FileOutputStream fileOut = new FileOutputStream("D:\test\test.db");
      //建立对象输入流
      ObjectOutputStream out = new ObjectOutputStream(fileOut);
      //输出反序列化对象
      out.writeObject(p);
      out.close();
      fileOut.close();
      System.out.printf("保存成功");
    }catch(IOException i){
      i.printStackTrace();
    }
}

进行反序列化

import java.io.*;

public class Main{
  public static void main(String [] args){
    /*从二进制文件中提取对象*/
    Persion persion = null;
    try{
      FileInputStream fileInputStream = new FileInputStream("D:\test\test.db");
      //建立对象输入流
      ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
      persion = (Persion) inputStream.readObject();
      inputStream.close();
      fileInputStream.close();
    }catch (ClassNotFoundException c){
      System.out.println("对象未找到");
      c.printStackTrace();
      return;
    } catch (FileNotFoundException e) {
      e.printStackTrace();
      return;
    } catch (IOException e) {
      e.printStackTrace();
      return;
    }
    System.out.println("反序列化对象.......");
    System.out.println("Name:"+persion.name);
    System.out.println("Age:"+persion.age);
    }
}

查看test.db文件的内容可以看见如下内容

其中 AC ED 00 05 是java 序列化内容的特征,其中00 05 是版本信息,base64编码后为ro0AB

反序列化漏洞Demo

在上面的Demo中可以看到,进行反序列化时会调用readObject()方法,如果readObject方法书写不当就会引发漏洞。

import java.io.*;

public class Main{
  public static void main(String [] args)throws Exception{
    Unsafeclass unsafeclass = new Unsafeclass();
    unsafeclass.name = "hhhhh";
    FileOutputStream fileOutputStream = new FileOutputStream("object");
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    //将对象写入object文件
    objectOutputStream.writeObject(unsafeclass);
    objectOutputStream.close();

    //从文件中反序列化对象
    FileInputStream fileInputStream = new FileInputStream("object");
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    //恢复对象
    Unsafeclass objectFormDisk = (Unsafeclass)objectInputStream.readObject();
    System.out.println(objectFormDisk.name);
    objectOutputStream.close();
  }
}
class Unsafeclass implements Serializable{
  public String name;
  //重写readObject()方法
  private void readObject(java.io.ObjectInputStream inputStream ) throws IOException , ClassNotFoundException{
    //执行默认的readObdect()方法
    inputStream.defaultReadObject();
    //执行打开计算器命令
    Runtime.getRuntime().exec("calc.exe");
  }
}

程序运行过程为:

  • UnsafeClass类背序列化进入object文件
  • 从object文件中恢复对象
  • 调用被恢复对象的readObject()方法
  • 命令被执行

这样看感觉并不会有人会这样写readobject()这个方法,而且一些成熟的框架都会有防范反序列化的方法,但仍有很大比例的反序列化漏洞,这主要是使用了不安全的库造成的。上面只是介绍了简单的Java反序列化过程,接下来会有一篇文章介绍反序列化漏洞检测方法以及复现一些经典反序列化漏洞。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Spring Boot实现文件上传的两种方式总结

    Spring Boot实现文件上传的两种方式总结

    应用开发过程中,文件上传是一个基础的扩展功能,它的目的就是让大家共享我们上传的文件资源,下面这篇文章主要给大家总结介绍了关于Spring Boot实现文件上传的两种方式,需要的朋友可以参考下
    2023-05-05
  • Redis中String字符串和sdshdr结构体超详细讲解

    Redis中String字符串和sdshdr结构体超详细讲解

    这篇文章主要介绍了Redis中String字符串和sdshdr结构体,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-04-04
  • mybatis深入讲解resultMap的定义及用法

    mybatis深入讲解resultMap的定义及用法

    MyBatis的每一个查询映射的返回类型都是ResultMap,当我们提供返回类型属性是resultType时,MyBatis会自动给我们把对应值赋给resultType所指定对象的属性,当我们提供返回类型是resultMap时,将数据库中列数据复制到对象的相应属性上,可以用于复制查询,两者不能同时用
    2022-04-04
  • java分页工具类的使用方法

    java分页工具类的使用方法

    这篇文章主要为大家详细介绍了java分页工具类的使用方法,稳定的分页效果,包括导航页码功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • Java虚拟机工作原理

    Java虚拟机工作原理

    本文主要介绍了Java虚拟机的工作原理。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • Spring.Net在MVC中实现注入的原理解析

    Spring.Net在MVC中实现注入的原理解析

    这篇文章主要介绍了Spring.Net在MVC中实现注入的原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java 日志打印的15个好建议

    Java 日志打印的15个好建议

    这篇文章主要介绍了Java日志打印的15个好建议,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • Java 二维码,QR码,J4L-QRCode 的资料整理

    Java 二维码,QR码,J4L-QRCode 的资料整理

    本文主要介绍Java 中二维码,QR码,J4L-QRCode,这里整理了详细的资料供大家学习参考关于二维码的知识,有需要的小伙伴可以参考下
    2016-08-08
  • java计算代码段执行时间的详细代码

    java计算代码段执行时间的详细代码

    java里计算代码段执行时间可以有两种方法,一种是毫秒级别的计算,另一种是更精确的纳秒级别的计算,这篇文章主要介绍了java计算代码段执行时间,需要的朋友可以参考下
    2022-08-08
  • 详解五种方式让你在java中读取properties文件内容不再是难题

    详解五种方式让你在java中读取properties文件内容不再是难题

    这篇文章主要介绍了详解五种方式让你在java中读取properties文件内容不再是难题 ,非常具有实用价值,需要的朋友可以参考下。
    2016-12-12

最新评论