【翻译】2序列化过滤

来源:Java官方文档

译者的话

由于译者的英文水平和编程水平都不高,不理解原文中的一些概念,一些句子也不知道如何翻译。对不知如何翻译的内容,译者使用了机器翻译,并在译文后面的括号中提供了原文。翻译如有错误,请参阅原文。有任何建议或意见,欢迎评论。

可以使用Java序列化过滤机制帮助避免反序列漏洞。有两种过滤器:基于模式的过滤器和自定义过滤器。

主题:

解决反序列化漏洞

应用程序接受并反序列化不受信任的数据很容易受到攻击。创建过滤器可以在反序列化对象之前筛选传入的序列化对象流。

当一个对象的状态被转换为字节流时,它就被序列化了。流可以发送到一个文件、一个数据库或者通过网络传输。如果一个Java对象的类或超类实现了 java.io.Serializable接口或 java.io.Externalizable子接口,它就可以被序列化。在JDK中,序列化用于许多场合,例如远程方法调用(RMI),用于进程间通信(IPC)协议(如Spring HTTP调用器)的自定义RMI、Java管理扩展(JMX)和Java消息传递服务(JMS)。

当一个对象从序列化形式转换为该对象的副本时,它就被反序列化了。确保转换安全是重要的。反序列化时要执行代码,因为被反序列化的类的 readObject方法可以包含自定义代码。可序列化的类,也称为”小工具类”,可以执行任意反射操作,比如创建类和调用类上的方法。如果的应用程序反序列化这些类,它们可能导致拒绝服务或远程代码执行。

可以在过滤器中指定应用程序接受或拒绝的类。也可以控制反序列化时的对象图尺寸和复杂性,以便对象的图不超过合理限制。(You can control the object graph size and complexity during deserialization so that the object graph doesn’t exceed reasonable limits.)(上句中的”graph”及以后出现”graph”均不知含义,为方便查找和修正错误,本文一律翻译为”图”)有两种方式实现过滤器:配置属性和代码。

除了使用过滤器,也可以用下面的方法防止他人利用反序列化漏洞:

  • 不反序列不受信任的数据。
  • 使用SSL加密和验证应用程序间的连接。
  • 在赋值前验证字段值,包使用 readObject方法检查对象不变量。(Validate field values before assignment, including checking object invariants by using the readObject method.)

注意:有可用于RMI的内置过滤器。但是,应该仅仅把这些内置过滤器当作起点。配置黑名单并且/或扩展白名单可以增强的应用使用RMI时的安全性。请参阅内置过滤器

Java序列化过滤器

Java序列化过滤机制筛选传入的序列化对象流,这可以增强程序安全性的健壮性。过滤器在传入的类反序列化时执行检查。

下列是JEP 290提出的Java序列化过滤机制的目标:

  • 提供一种方法,将可以反序列化的类缩小到适合上下文的类集合。(Provide a way to narrow the classes that can be deserialized down to a context-appropriate set of classes.)
  • 在反序列化时,为过滤器提供图的尺寸和复杂性的指标,以验证正常的图行为。(Provide metrics to the filter for graph size and complexity during deserialization to validate normal graph behaviors.)
  • 允许RMI导出的对象验证调用中期望的类。(Allow RMI-exported objects to validate the classes expected in invocations.)

下面是实现序列化过滤器的方式:

  • 基于模式的过滤器不需要修改应用。它们由一系列模式组成,这些模式在属性、配置文件或命令行中定义。基于模式的过滤器可以接受或拒绝特定的类、包或模块,也可以限制数组大小、图深度、总引用数量和流大小。典型用法是把可能危害Java运行环境的类加入黑名单。基于模式的过滤器是为进程中的一个应用程序或所有应用程序定义的。(Pattern-based filters are defined for one application or all applications in a process.)(上句中的”progress”及以后出现的”progress”均不知含义,为方便查找和修正错误,本文一律翻译为”进程”)
  • 自定义过滤器使用 ObjectInputFilter API实现。它们比基于模式的过滤器的控制更加精细,因为它们可以为每个 ObjectInputStream定制。自定义过滤器可以设置在单个输入流上或进程中的所有流上。(Custom filters are set on an individual input stream or on all streams in a process.)

流中的每个新对象都会调用过滤机制。如果有多个激活的过滤器(进程级过滤器(process-wide filter)、应用过滤器或特定流过滤器)存在,只会调用最贴近当前场景的过滤器。

在大多数情况下,自定义过滤器应该检查是否设置了进程级过滤器。如果有进程级过滤器,除非它的结果是 UNDECIDED,否则自定义过滤器应该调用进程级过滤器并且使用它的结果。

从JDK 9开始,以及从8u121、7u131和6u141开始的Java CPU版本都支持序列化过滤器。

白名单和黑名单

在基于模式的过滤器和自定义过滤器都可以使用白名单和黑名单。黑/白名单能用主动或防御性的方法保护应用。

主动方法是使用白名单允许被识别的和受信任的类通过。可以在开发应用时在代码中实现白名单,或者在后面使用基于模式的过滤器实现白名单。这种方法适合只需要处理较少类的应用。通过指定允许的类、包或模块来实现白名单。

创建基于模式的过滤器

使用基于模式的过滤器时用修改应用代码。可以在配置文件中添加进程级过滤器,或者在 java命令行中添加特定应用过滤器。

基于模式的过滤器由一系列模式组成。每个模式根据类名或资源限制判断是否接受流中的对象。(Each pattern is matched against the name of a class in the stream or a resource limit.)基于类的模式和资源限制模式可以写在一个过滤器字符串中,每个模式用分号(;)分隔。

基于模式的过滤器语法

由模式组成的过滤器应遵循以下指南:

  • 使用分号分隔模式。例如:

  • 空格很重要,也是模式的一部分。

  • 把限制放在过滤器字符串的首位。无论它们在字符串的什么位置,它们都会首先计算,所以把它们放在字符串的首位以强化人们对顺序的认知。如果没有限制,就会按照从左往右的用模式验证。(译注:限制包括对输入流中对象的数组长度、引用数量、图深度等的限制)
  • 如果一个类匹配以 !开头的模式,它将被拒绝。如果一个类匹配的模式开头没有 !,它将被接受。下面的过滤器拒绝了 pattern1.MyClass但是接受了 pattern2.MyClass

  • 通配符( *)表示任意类,下面是一些示例:

  • *匹配任意类
  • mypackage.*匹配 mypackage中的所有类
  • mypackage.**匹配 mypackage和它的子包中的有所类
  • text*匹配任意以text开头的类

没有匹配任何过滤器的类将被接受。如果只想接受特定类,过滤器必须拒绝任何不匹配的东西。在类过滤器的最后使用”!*”可以拒绝所有未指定的类。

基于模式的过滤器限制

基于模式的过滤器仅能做到简单的接受和拒绝。这些过滤器有一些限制。例如:

  • 模式无法为不同的类的数组规定不同的大小。
  • 模式不能筛选类的超类或接口。
  • 模式没有状态,不能根据先前从流中反序列化的类决定当前类是接受还是拒绝。

为单个应用定义基于模式的过滤器

可以为单个应用程序将基于模式的过滤器定义成系统属性。系统属性将会覆盖安全属性(Security Property)的值。(A system property supersedes a Security Property value.)

要创建一个只应用在单次Java调用的应用程序的过滤器,只需要在命令行中定义 jdk.serialFilter系统属性。

下面是一个限制单个应用程序资源使用量的示例:

为进程中的所有应用程序定义基于模式的过滤器(Define a Pattern-Based Filter for All Applications in a Process)

可以在安全属性定义一个基于模式的过滤器,该过滤器是为进程中所有应用定义的。系统属性将会覆盖安全属性(Security Property)的值。

定义类过滤器

可以创建一个全局的基于模式的类过滤器。例如,一个使用通配符的类名或包名的模式。

在下例中,过滤器拒绝了一个包中的一个类( !example.somepackage.SomeClass),并且接受该包中的所有其他类:

上例中的过滤器除了 example.somepackage.*中的类,接受所有其他类。要拒绝其他所有类,在末尾加上”!*”:

定义资源限制过滤器

资源过滤器限制图的复杂性和尺寸。可以用下面的参数创建过滤器限制每个应用程序的资源使用量:

  • 限制数组长度。例如: maxarray=100000
  • 限制图的深度。例如: maxdepth=20
  • 限制图中对象引用的数量。例如: maxrefs=500
  • 限制流的字节数。例如: maxbytes=500000

创建自定义过滤器

自定义过滤器是在应用程序代码中定义的过滤器。自定义过滤器可以设置单个流上或一个进程中的所有流。可以将自定义过滤器实现为一个模式、一个方法、一个lambda表达式或一个类。

读取序列化对象流

可以在一个 ObjectInputStream上设置一个自定义过滤器,或者通过设置进程级过滤器将相同的过滤器设置到每一个流上。(You can set a custom filter on one ObjectInputStream, or, to apply the same filter to every stream, set a process-wide filter.)。如果一个 ObjectInputStream上没有过滤器,它将会使用进程级过滤器(如果有的话)。

解码流时,执行下列操作:

  • 在实例化和反序列化流中的每个新对象之前,过滤器被调用。
  • 流中的每个类在被解析时,过滤器被调用。流中的每个超类和接口在被解析时都会单独调用过滤器。(The filter can examine each class referenced in the stream, including the class of objects to be created, supertypes of those classes, and their interfaces.)
  • 过滤器可以检查流中引用的每个类,包括要创建的对象的类、该类的超类和它们的接口。(For each class in the stream, the filter is called with the resolved class. It is called separately for each supertype and interface in the stream.)
  • 当校验数组类型和数组长度时(无论是基本类型数组、字符串数组还是对象数组),过滤器被调用。
  • 每从流中读取对象的一个引用,过滤器都会检查深度、引用数和流长度。深度从1开始,每个嵌套对象会增加深度,过滤器从嵌套中返回则深度减小。
  • 过滤器不会检查流中具体编码的基本类型或 java.lang.String实例。(The filter is not called for primitives or for java.lang.String instances that are encoded concretely in the stream.)
  • 过滤器返回”接受”、”拒绝”或”未决定”状态。
  • 如果启用了日志记录,则会记录过滤器操作。

如果一个对象没被过滤器拒绝,就会被接受。

在单个流上设置自定义过滤器

当流的输入不受信任并且过滤器限制类的种类或实施约束时,可以在单个 ObjectInputStream上设置过滤器。例如,可以要求流仅包含数字、字符串和其他应用程序指定的类型。

使用 setObjectInputFilter方法设置自定义过滤器。设置自定义过滤器必须在从流中读取对象之前。

在下例中, setObjectInputFilter方法调用了 dateTimeFilter方法(In the following example, the setObjectInputFilter method is invoked with the <code>dateTimeFilter</code> method.)(译注:从代码上来看,是 setObjectInputFilter方法将 dateTimeFilter方法设置成了过滤器)。此过滤器仅接受 java.time包中的类。 dateTimeFilter方法的定义在把方法设置为自定义过滤器的示例代码中。

设置进程级的自定义过滤器

你可以设置应用于全部 ObjectInputStream的进程级过滤器,只要特定流没有覆盖它,它就会被调用。要实现过滤器,需要确定应用程序所需的类型和条件。一般来说,进程级过滤器用于拒绝特定的类或包,或限制数组大小、图深度或图的总大小。

进程级过滤器只需使用 ObjectInputFilter.Config 类的方法设置一次。过滤器可以是类、lambda 表达式、方法引用或模式的实例。

下例中,将 lambda 表达式设置为进程级过滤器。

下例中,将方法引用设置为进程级过滤器:

将模式设置为自定义过滤器

可以使用 ObjectInputFilter.Config.createFilter方法创建基于模式的自定义过滤器(情况简单时这很方便)。可以以系统属性或安全属性的形式创建基于模式的过滤器。用方法或lambda表达式实现基于模式的过滤器则更灵活。

过滤器模式可以接受或拒绝特定的类、包、模块,并且可以限制数组大小、图深度、总引用数量和流大小。模式不会匹配类的超类型或接口。

在下例中,过滤器允许 example.File类并且拒绝 example.Directory类。

下例仅允许 example.File类。其他类都被拒绝。

将类设置为自定义过滤器

可以用实现了 java.io.ObjectInputFilter接口的类、lambda表达式或方法实现自定义过滤器。

过滤器通常是无状态的,对输入参数的检查互相之间没有关联。但是有状态的过滤器是可实现的。例如,可以实现这样的过滤器,在调用 checkInput方法之间维护状态,以对流中的项目进行计数。

在下例中, FilterNumber类仅允许 Number类的实例对象,并拒绝其他对象。

在上例中:

  • checkInput方法的参数是一个 ObjectInputFilter.FilterInfo对象。可以用该对象的方法访问要检查的类、数组大小、当前深度、对现有对象的引用数以及到目前为止读取的流大小。
  • 如果 serialClass方法的返回值不是null,则表明正在创建新对象。然后检查该对象的类是不是 Number。若是,则接受,否则拒绝。
  • 参数不符合以上条件则返回 UNDECIDED。如果还有过滤器,则继续反序列化,直到该对象被接收或拒绝。如果没有其他过滤器,则接受该对象。

将方法设置为自定义过滤器

可以用方法实现自定义过滤器。使用方法引用而不是内联的lambda表达式。

为单个流设置自定义过滤器中的示例代码使用了下例中定义的 <code>dateTimeFilter</code>方法。

示例:只允许于java.base 模块中的类的过滤器

此自定义过滤器(作为方法实现)仅允许在JDK的基本模块中找到的类通过。此示例适用于JDK 9及更高版本。

内置过滤器

JDK中有适用于Java远程方法调用(RMI)注册中心、RMI分布式垃圾回收器和Java管理扩展(JMX)的过滤器。应该为RMI注册中心和RMI分布式垃圾回收器指定自己的过滤器,以增强安全性。

RMI 注册中心的过滤器

注意:只把这些内置过滤器当作起点。可以编辑 sun.rmi.registry.registryFilterjdk.serialFilter系统属性来配置黑名单和/或扩展白名单,这能增强RMI 注册中心的安全性。若要保护整个应用程序,请将模式添加到 jdk.serialFilter全局系统属性,以增强对没有自己的自定义过滤器的其他序列化用户的保护。

RMI 注册中心具有内置的白名单过滤器,该过滤器仅允许在注册中心中绑定的对象通过。允许的对象包括 java.rmi.Remotejava.lang.Numberjava.lang.reflect.Proxyjava.rmi.server.UnicastRefjava.rmi.activation.ActivationIdjava.rmi.server.UIDjava.rmi.server.RMIClientSocketFactoryjava.rmi.server.RMIServerSocketFactory类的实例。

内置过滤器包括大小限制:

请在 sun.rmi.registry.registryFilter系统属性用模式定义一个过滤器,取代内置过滤器。如果定义的过滤器要么接受传递给过滤器的类,要么拒绝类或尺寸,那么内置过滤器不会调用。如果用户定义的过滤器既不接受也不拒绝任何内容,则内置过滤器会被调用。

用于 RMI 分布式垃圾回收器的过滤器

注意:仅将这些内置过滤器当作起点。编辑 sun.rmi.transport.dgcFilter系统属性可以配置黑名单和/或扩展白名单,这能为分布式垃圾回收器添加保护。若要保护整个应用程序,请将模式添加到jdk.serialFilter全局系统属性,以增强对没有自己的自定义过滤器的其他序列化用户的保护。

RMI 分布式垃圾回收器有一个内置的白名单过滤器,该过滤器接受有限的一组类。这组类包括 java.rmi.server.ObjIDjava.rmi.server.UIDjava.rmi.dgc.VMIDjava.rmi.dgc.Lease类的实例。

内置过滤器包括大小限制:

请在 sun.rmi.transport.dgcFilter系统属性用模式定义过滤器,用以取代内置过滤器。如果过滤器接受传递给过滤器的类,或者拒绝类或大小,则不会调用内置过滤器。如果取代过滤器不接受或拒绝任何内容,则调用内置过滤器。

用于 JMX 的过滤器

注意:仅将这些内置过滤器当作起点。编辑 jmx.remote.rmi.server.serial.filter.pattern管理属性可以配置黑名单和/或扩展白名单,这能增加对JMX的额外保护。若要保护整个应用程序,请将模式添加到 jdk.serialFilter全局系统属性,以增强对没有自己的自定义过滤器的其他序列化用户的保护。

JMX 有一个内置的过滤器,该过滤器仅允许一组有限的类作为反序列化参数通过 RMI发送到服务器。该过滤器默认禁用。若要启用该过滤器,请在 jmx.remote.rmi.server.serial.filter.pattern管理属性用模式定义过滤器。

该模式必须包括允许通过 RMI 作为参数发送到服务器的类型,以及它们所依赖的所有类型,外加 javax.management.ObjectNamejava.rmi.MarshalledObject类型。例如,若要将允许的类集合限制为Open MBean类型及其所依赖的类型,请将以下行添加到 management.properties文件中。

记录过滤器行为

可以打开日志记录以记录对序列化过滤器的调用的初始化、拒绝和接受。使用日志输出作为诊断工具,以查看正在反序列化的内容,并在配置白名单和黑名单时确认的设置。(Use the log output as a diagnostic tool to see what’s being deserialized, and to confirm your settings when you configure whitelists and blacklists.)

启用日志记录后,过滤器操作将记录到 java.io.serialization序列化记录器中。

若要启用序列化过滤器的日志,请编辑 $JDK_HOME/conf/logging.properties文件。

要记录被拒绝的调用,请添加

若要记录所有过滤器结果,请添加

Original: https://www.cnblogs.com/cnblog-user/p/16462329.html
Author: Halloworlds
Title: 【翻译】2序列化过滤

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/712902/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 1、使用thymeleaf给foreach遍历的元素加一个id2、在th:href中使用${}

    备注:在jsp之中,类似的是varStatus 需求: 有时候,我们需要操作foreach遍历后的元素,比如说,使用js给遍历的某个元素绑定点击事件;那么如何通过标签的id找到那个…

    技术杂谈 2023年7月24日
    077
  • -source 1.5 中不支持 diamond 运算符

    maven编译时报”-source 1.5 中不支持 diamond 运算符”错误 D:\maven3.5.3\conf\settings.xml ————…

    技术杂谈 2023年5月31日
    083
  • 麦克风采集与播放 (源码)

    在网络聊天系统中,采集麦克风的声音并将其播放出来,是最基础的模块之一。本文我们就介绍如何快速地实现这个基础模块。 有几个与声音采集和播放相关的专业术语必须要先了解一下,否则,后面的…

    技术杂谈 2023年6月1日
    0122
  • 上周热点回顾(7.25-7.31)

    热点随笔: · 手把手带你实现基于 Vite+Vue3 的在线Excel表格系统 (葡萄城技术团队)· 使用Three.js实现炫酷的赛博朋克风格3D数字地球大屏 🌐 (Drago…

    技术杂谈 2023年5月31日
    097
  • JAVA抓取百度热搜榜实时数据

    背景:[JAVA]前几天面试超碧,聊到其接触的项目,有抓取各类排行的实时数据,进行多国语言翻译,抓取目前比较火的语言是php、go,由于目前工作使用JAVA,因此也模拟实现了一下抓…

    技术杂谈 2023年7月24日
    099
  • Locust的使用二

    Locust的使用一 通过命令参数可以配置Locust运行方式 文档 https://docs.locust.io/en/stable/configuration.html#com…

    技术杂谈 2023年5月31日
    086
  • Java — 注解

    Java 注解(Annotation)又称为 Java 标注,是 Java5 开始支持加入源代码的特殊语法元数据。 Java 语言中的类、方法、变量、参数和包等都可以被标注。 Ja…

    技术杂谈 2023年7月11日
    080
  • i++和++i

    ++ 是 自增运算符 不给变量赋值 最后 i 的值都是一样的 给变量赋值 i++先赋值 后自增 ++i 先自增 后赋值 不能理解请 一条++操作配合一条输出语句 其他6条注释掉 执…

    技术杂谈 2023年6月21日
    077
  • python工具–获取盛科交换机端口模块类型,波长,传输距离等信息

    个人博客地址 http://www.darkghost.life 交换机端口模块信息对应的OID节点为各厂商私有节点,获取其他厂商信息需要把OID进行替换 1 #! /usr/bi…

    技术杂谈 2023年7月25日
    0123
  • flutter创建项目

    一、终端方式 1、创建flutter项目: 出现: 2、先直接打开Xcode自带iOS模拟器,否则会运行在macOS (macos)或Chrome (chrome)上。 3、运行项…

    技术杂谈 2023年6月1日
    098
  • Modern Cpp记录

    cpp;gutter:true;</p> <h1>include</h1> <p>include</p> <h1&…

    技术杂谈 2023年5月31日
    090
  • Datahub小结

    往datahub发送数据时,建议使用Producer。好处是不用设置shardId,这样datahub在增加或减少shard时,业务代码都不需要变更。另外datahub的shard…

    技术杂谈 2023年5月30日
    0102
  • python练习题:将列表中的大写字母转换成小写

    将列表中的大写字母转换成小写如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,L1 = [‘Hello’, ‘World’, 18, ‘Apple’,…

    技术杂谈 2023年7月24日
    088
  • Lombok中关于@Data的使用解析

    public class TestB extends TestA {private String name;private int age;public TestB() {}pub…

    技术杂谈 2023年5月30日
    092
  • PyTorch 介绍 | LEARN THE BASICS

    大多数机器学习流程都包括数据、创建模型、优化模型参数,以及保存训练模型工作。该教程向你介绍一个在PyTorch上实现的完整的机器学习工作流,并提供了了解这些概念详细信息的链接。 我…

    技术杂谈 2023年7月25日
    076
  • 关于SQL语句的执行顺序

    首先,要清楚在一select语句中都会用到哪些关键字: 其次,要知道每执行一步就会生成一个对应的虚拟表: 明白这两点再看执行的先后顺序 1.from语句:不管是什么SQL语句,都得…

    技术杂谈 2023年7月11日
    095
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球