首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Java序列化、反序列化、反序列化漏洞

编程知识
2024年09月25日 08:52

目录

1 序列化和反序列化

1.1 概念

Java 中序列化的意思是将运行时的对象转成可网络传输或者存储的字节流的过程。而反序列化正相反,是把字节流恢复成对象的过程。

1.2 序列化可以做什么?

  1. 持久化存储:将对象状态保存到存储设备(如硬盘)中,以便于后续读取使用。
  2. 网络传输:将对象转换成字节流,通过网络发送给另一个 JVM 实例,接收方再将字节流转回对象。
  3. 深度复制:通过序列化与反序列化可以实现对象的深复制,即创建一个新的对象,并且新对象的数据与原对象相同,但是它们在内存中的地址不同。

3 实现方式

3.1 Java 原生方式

step1:实现 Serializable 接口

要使一个类的对象能够被序列化,只需要让这个类实现 Serializable 接口即可。Serializable 是一个标记接口,它没有定义任何方法。例如:

public class Person implements Serializable {
    // 可选,用于版本控制
    private static final long serialVersionUID = 1L; 
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
        "name='" + name + ''' +
        ", age=" + age +
        '}';
    }

}

step2:使用 ObjectOutputStream#writeObject() 方法序列化。例如:

public static void main(String[] args) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\test.bin"));
    oos.writeObject(new Person("zhangsan",18));
}

step3:使用 ObjectInputStream#readObject() 方法反序列化。例如:

public static void main(String[] args) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get("D:\test.bin")));
    Person p = (Person) ois.readObject();
    System.out.println(p);
}
// 打印 Person{name='zhangsan', age=18}

3.2 第三方方式

使用 Java 原生序列化方式序列化的对象只能被 Java 读取(反序列化),所以可以考虑先把对象转成一种通用的格式——如 JSON 字符串,然后把 JSON 字符串转成字节流进行网络传输,从而实现跨平台或者跨语言。

这个时候就可以使用市面上开源的序列化工具了,比如 JSON、Xml、hessian等。

4 反序列化漏洞

反序列化是把数据流转成对象,那么万一数据流被人恶意加工过呢?

拿 Java 原生的反序列化举例,反序列化需要调用 ObjectInputStream#readObject() 方法,但是如果数据流的对象自己重写了 readObject(),那 Java 便会调用自己的这个 readObject() 方法,这就给了攻击者可乘之机,他们就能在自己的 readObject() 方法里写攻击代码。

我们改造一下上面例子里的 Person 类:

@Data
public class Person implements Serializable {
    // 可选,用于版本控制
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
        "name='" + name + ''' +
        ", age=" + age +
        '}';
    }

    // 重写了 readObject 方法,反序列化时便会调用此处
    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject(); //这一步是先让反序列化读取的时候按照默认的方法执行
        Runtime.getRuntime().exec("calc"); //这一步是攻击代码,作用是打开windows系统计算器
    }
}

此时再去执行反序列化便会打开系统的计算器,如果把打开计算器改成别的攻击代码,攻击者便能实现对系统的攻击。

为什么 Java 会允许我们重写 readObject,并让服务端调用我们的 readObject 呢?其实这么做的原因是为了方便定制化某些类的序列化方法,比如 HashMap 类就重写了 readObject 方法,原因是由于 HashMap 内部使用了一些特定的数据结构(如数组和链表/红黑树),直接反序列化可能无法正确地恢复这些内部结构。因此,readObject 方法会负责根据序列化的数据正确地重建这些内部结构。

From:https://www.cnblogs.com/GilbertDu/p/18430691
本文地址: http://www.shuzixingkong.net/article/2287
0评论
提交 加载更多评论
其他文章 关于建表字段是否该使用not null这个问题你怎么看?
大家好,我是 V 哥,在数据库设计中,是否使用 NOT NULL 是一个非常重要的决策,直接影响数据完整性、查询性能以及业务逻辑的复杂度。使用 NOT NULL 的关键在于理解业务需求和具体场景。 下面V哥通过一些场景来分析什么时候应该使用 NOT NULL,什么时候允许 NULL。一起聊聊经验之谈
ArgoWorkflow教程(五)---Workflow 的多种触发模式:手动、定时任务与事件触发
上一篇我们分析了argo-workflow 中的 archive,包括 流水线GC、流水线归档、日志归档等功能。本篇主要分析 Workflow 中的几种触发方式,包括手动触发、定时触发、Event 事件触发等。 1. 概述 Argo Workflows 的流水线有多种触发方式: 手动触发:手动提交一
ArgoWorkflow教程(五)---Workflow 的多种触发模式:手动、定时任务与事件触发 ArgoWorkflow教程(五)---Workflow 的多种触发模式:手动、定时任务与事件触发 ArgoWorkflow教程(五)---Workflow 的多种触发模式:手动、定时任务与事件触发
从零开始学机器学习——了解回归
在本文中,我们探讨了回归分析在统计学和数据分析中的重要性和应用。线性回归和逻辑回归作为两种主要的回归分析方法,分别适用于不同类型的数据建模和预测需求。通过数学建模,它们能够揭示变量之间的关系,并且在实际应用中展现了强大的预测能力。
从零开始学机器学习——了解回归 从零开始学机器学习——了解回归 从零开始学机器学习——了解回归
我是如何开发一款支持IDEA、PyCharm、Android Sutdio 等JB全家桶的摸鱼插件的
公众号「古时的风筝」,专注于后端技术,尤其是 Java 及周边生态。 个人博客:www.moonkite.cn 大家好,我是风筝 前些天做了一款支持 Jetbrains 大部分 IDE 的摸鱼插件- 一款IDE摸鱼插件,没想到出乎意料的没什么人用,当初说 VsCode 里面的养宠物的插件时,一大堆人
我是如何开发一款支持IDEA、PyCharm、Android Sutdio 等JB全家桶的摸鱼插件的 我是如何开发一款支持IDEA、PyCharm、Android Sutdio 等JB全家桶的摸鱼插件的 我是如何开发一款支持IDEA、PyCharm、Android Sutdio 等JB全家桶的摸鱼插件的
Java Web 拾遗
许是年纪大了,老是回忆起以前的点点滴滴。翻看当初的代码,如同偶遇多年未见的前女友,曾经一起深入交流的情谊在颔首之间消散,令人烦躁。 今天就来聊聊老生常谈的 Java Web 开发。缘于一个简单的Spring Boot项目改造,笔者看着一坨注解和配置,苦于拾掇记忆的痛苦,择其一二记录,纪念逝去的青春。
C# 开源浏览器性能提升,体验Chrome级速度
前言 使用 C# 和 CefSharp 开发的全功能网页浏览器。 项目介绍 SharpBrowser 是目前最快的开源 C# 网页浏览器! 采用了轻量级的 CEF 渲染器,在呈现网页时甚至比 Google Chrome 更快。 我们对比了所有可用的.NET 浏览器引擎,最终选择了高性能的 CefSh
C# 开源浏览器性能提升,体验Chrome级速度 C# 开源浏览器性能提升,体验Chrome级速度 C# 开源浏览器性能提升,体验Chrome级速度
使用.NET并行任务库(TPL)与并行Linq(PLINQ)充分利用多核性能
前言 最近比较闲,(项目要转Java被分到架构组,边缘化人员,无所事事 哈哈哈哈) 记录一下前段时间用到的.NET框架下采用并行策略充分利用多核CPU进行优化的一个方法 起因是项目中有个结算的方法,需要汇总一个月的数据在内存中进行计算,统计,分组 ,然后产生新的数据 在某个客户那部署后发现,这个方法
使用.NET并行任务库(TPL)与并行Linq(PLINQ)充分利用多核性能 使用.NET并行任务库(TPL)与并行Linq(PLINQ)充分利用多核性能 使用.NET并行任务库(TPL)与并行Linq(PLINQ)充分利用多核性能
keycloak~关于授权码认证中的scope的实践
前言 1. scope 参数的作用 定义权限:scope 用于声明请求访问的资源和权限。常见的值包括 openid、profile、email 等。 影响返回的数据:如果你在授权请求中指定了某些 scope,在后续的 token 请求中,Keycloak 会根据这些 scope 返回相应的信息。 o
keycloak~关于授权码认证中的scope的实践