Deserialization Cheat Sheet / 反序列化技巧指南¶
Introduction / 介绍¶
This article is focused on providing clear, actionable guidance for safely deserializing untrusted data in your applications.
本文旨在提供清晰、可操作的建议,以帮助您在应用程序中安全地反序列化不受信任的数据。
What is Deserialization / 什么是反序列化¶
Serialization is the process of turning some object into a data format that can be restored later. People often serialize objects in order to save them for storage, or to send as part of communications.
序列化是将某些对象转换为可以稍后恢复的数据格式的过程。人们通常将对象序列化以保存它们以供存储,或作为通信的一部分发送。
Deserialization is the reverse of that process, taking data structured in some format, and rebuilding it into an object. Today, the most popular data format for serializing data is JSON. Before that, it was XML.
反序列化是此过程的逆过程,它将结构化的数据转换为对象。今天,最流行的数据格式用于序列化数据是JSON。在此之前,它是XML。
However, many programming languages have native ways to serialize objects. These native formats usually offer more features than JSON or XML, including customization of the serialization process.
然而,许多编程语言都有本地的序列化对象方式。这些本地格式通常比JSON或XML提供更多功能,包括自定义序列化过程。
Unfortunately, the features of these native deserialization mechanisms can sometimes be repurposed for malicious effect when operating on untrusted data. Attacks against deserializers have been found to allow denial-of-service, access control, or remote code execution (RCE) attacks.
不幸的是,当操作不受信任的数据时,这些本地反序列化机制的功能有时可以被重新用于恶意目的。发现针对反序列化器的攻击可以允许拒绝服务、访问控制或远程代码执行(RCE)攻击。
Guidance on Deserializing Objects Safely / 安全反序列化对象指南¶
The following language-specific guidance attempts to enumerate safe methodologies for deserializing data that can't be trusted.
以下针对特定语言的指导旨在列举不可信数据的反序列化安全方法。
PHP¶
Clear-box Review / 明盒审查¶
Check the use of unserialize() function and review how the external parameters are accepted. Use a safe, standard data interchange format such as JSON (via json_decode() and json_encode()) if you need to pass serialized data to the user.
检查unserialize()函数的使用情况,并审查外部参数的接受方式。如果您需要将序列化数据传递给用户,请使用安全的、标准的数据交换格式,如JSON(通过json_decode()和json_encode())。
Python¶
Opaque-box Review / 暗盒审查¶
If the traffic data contains the symbol dot . at the end, it's very likely that the data was sent in serialization. It will be only true if the data is not being encoded using Base64 or Hexadecimal schemas. If the data is being encoded, then it's best to check if the serialization is likely happening or not by looking at the starting characters of the parameter value. For example if data is Base64 encoded, then it will most likely start with gASV.
如果流量数据以符号点.结尾,那么数据很可能是以序列化的形式发送的。如果数据没有使用Base64或十六进制模式进行编码,则这将是真的。如果数据正在编码,那么最好通过查看参数值的起始字符来检查序列化是否可能发生。例如,如果数据是Base64编码的,那么它很可能会以gASV开头。
Clear-box Review / 明盒审查¶
Review the following APIs for untrusted input:
请审查以下API以检查不可信的输入:
-
Uses of
pickle.load()orpickle.loads(). Unpickling can execute arbitrary code; never unpickle untrusted data.pickle.loads()expects bytes-like input, not a Python 3 string.
中文:使用pickle.load()或pickle.loads()。反序列化可以执行任意代码;切勿反序列化不受信任的数据。pickle.loads()期望字节类似输入,而不是Python 3字符串。 -
Uses of PyYAML's unsafe loaders, such as
yaml.unsafe_load()oryaml.load()withLoader=yaml.LoaderorLoader=yaml.UnsafeLoader. For untrusted YAML, useyaml.safe_load(), and do not register custom constructors that allow arbitrary object creation. Current PyYAML requires an explicitLoaderargument foryaml.load().
中文:使用 PyYAML 的不安全加载器,例如yaml.unsafe_load()或yaml.load()并设置Loader=yaml.Loader或Loader=yaml.UnsafeLoader。对于不受信任的 YAML,请使用yaml.safe_load()(https://pyyaml.org/wiki/PyYAMLDocumentation#the-yaml-package),并且不要注册允许任意对象创建的自定义构造函数。当前的 PyYAML 需要yaml.load()显式传递Loader参数。 -
Uses of
jsonpickle.decode()with untrusted input.
中文:使用 jsonpickle.decode() 解析不受信任的输入。
Java¶
For historical research on Java deserialization and defensive allowlisting, see Java Deserialization Attacks — German OWASP Day 2016.
关于Java反序列化和防御性允许列表的历史研究,请参阅Java反序列化攻击 — 德国OWASP Day 2016。
The following techniques can reduce risks when using Java's Serializable format.
以下技术可以在使用Java的Serializable格式时降低风险。
Implementation advice:
实现建议:
- Configure serialization filters with an application-specific class allowlist and resource limits before reading objects.
中文:在读取对象之前,使用应用程序特定的类白名单和资源限制配置 序列化过滤器。 - If maintaining a
resolveClass()override, account for its limitations below; class checks alone do not bound resource consumption.
中文:如果维护resolveClass()的覆盖,需考虑其以下限制;仅进行类检查并不能限制资源消耗。
Clear-box Review / 明盒审查¶
Be aware of the following Java API uses for potential serialization vulnerability.
请注意以下Java API的使用,以防范潜在的序列化漏洞。
1. XMLdecoder with external user defined parameters
中文:使用外部用户定义参数的XMLdecoder
2. XStream with fromXML method (xstream version <= v1.4.6 is vulnerable to the serialization issue)
中文:使用XStream的fromXML方法(xstream版本<=v1.4.6易受序列化问题影响)
3. ObjectInputStream with readObject
中文:ObjectInputStream读取对象
4. Uses of readObject, readObjectNoData, readResolve or readExternal
中文:使用readObject、readObjectNoData、readResolve或readExternal
5. ObjectInputStream.readUnshared
6. Serializable
中文:可序列化
Opaque-box Review / 暗盒审查¶
If the captured traffic data includes the following patterns, it may suggest that the data was sent in Java serialization streams:
如果捕获的流量数据包含以下模式,可能表明数据是通过Java序列化流发送的:
AC ED 00 05in Hex
中文:十六进制中的AC ED 00 05rO0in Base64
中文:Base64中的rO0Content-typeheader of an HTTP response set toapplication/x-java-serialized-object
中文:HTTP 响应的Content-type头设置为application/x-java-serialized-object
Prevent Data Leakage and Trusted Field Clobbering / 防止数据泄露和信任字段覆盖¶
If there are data members of an object that should never be controlled by end users during deserialization or exposed to users during serialization, they should be declared as the transient keyword (section Protecting Sensitive Information).
如果一个对象的数据成员在反序列化期间不应由最终用户控制或在序列化期间暴露给用户,则应将其声明为transient关键字(章节 保护敏感信息)
For a class that defined as Serializable, the sensitive information variable should be declared as private transient.
对于定义为可序列化的类,敏感信息变量应声明为private transient
For example, the class myAccount, the variables 'profit' and 'margin' were declared as transient to prevent them from being serialized.
例如,对于myAccount类,变量profit和margin被声明为transient以防止它们被序列化
public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient
....
Prevent Deserialization of Domain Objects / 防止域对象的反序列化¶
Some of your application objects may be forced to implement Serializable due to their hierarchy. To guarantee that your application objects can't be deserialized, a readObject() method should be declared (with a final modifier) which always throws an exception:
由于层次结构,您的某些应用程序对象可能被迫实现Serializable。为了确保您的应用程序对象不能被反序列化,应声明一个(带有final修饰符的)readObject()方法,该方法始终抛出异常:
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
Harden Your Own java.io.ObjectInputStream / 强化您自己的java.io.ObjectInputStream¶
The java.io.ObjectInputStream class is used to deserialize objects. A custom class-resolution allowlist may be useful if:
java.io.ObjectInputStream类用于反序列化对象。如果以下情况成立,自定义类解析白名单可能很有用:
- you can change the code that does the deserialization;
中文:您可以更改执行反序列化的代码; - you know what classes you expect to deserialize.
中文:您知道您期望反序列化哪些类。
The general idea is to override ObjectInputStream.resolveClass() to restrict ordinary class resolution during deserialization.
一般思路是覆盖 ObjectInputStream.resolveClass() 方法以限制反序列化过程中的普通类解析。
This does not check every object: the serialization specification handles strings separately and resolves dynamic proxy class descriptors through resolveProxyClass().
这不会检查每个对象:序列化规范 会单独处理字符串,并通过 resolveProxyClass() 方法解析动态代理类描述符。
The following example allows only Bicycle through resolveClass(). It is an illustrative class check, not a complete deserialization defense:
以下示例仅允许通过 resolveClass() 的 Bicycle 类。这是一个说明性的类检查,而不是完整的反序列化防御:
public class LookAheadObjectInputStream extends ObjectInputStream {
public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}
/**
* Restrict ordinary class resolution to our expected Bicycle class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}
Use serialization filtering to combine a class allowlist with limits on graph depth, references, array lengths, and stream bytes. Also bound the serialized input size separately: filters are not called for concretely encoded strings or primitives. Filtering does not make arbitrary untrusted deserialization safe.
使用 序列化过滤 来结合类允许列表和图深度、引用、数组长度以及流字节的限制。此外,单独绑定序列化输入大小:对于具体编码的字符串或原始数据类型,不会调用过滤器。过滤并不能使任意不受信任的反序列化变得安全。
More complete implementations of this approach have been proposed by various community members:
该方法的更完整实现已被社区成员提出:
- NibbleSec - a library that allows creating lists of classes that are allowed to be deserialized
- IBM - the seminal protection, written years before the most devastating exploitation scenarios were envisioned.
- Apache Commons IO classes
Harden All java.io.ObjectInputStream Usage with an Agent / 使用代理强化所有 java.io.ObjectInputStream 使用¶
As mentioned above, the java.io.ObjectInputStream class is used to deserialize objects. It's possible to harden its behavior by subclassing it. However, if you don't own the code or can't wait for a patch, using an agent to weave in hardening to java.io.ObjectInputStream is the best solution.
如上所述,java.io.ObjectInputStream 类用于反序列化对象。可以通过继承它来强化其行为。然而,如果您不拥有代码或无法等待补丁,使用代理向 java.io.ObjectInputStream 中织入强化措施是最佳解决方案。
Globally changing ObjectInputStream is only safe for block-listing known malicious types, because it's not possible to know for all applications what the expected classes to be deserialized are. Fortunately, there are very few classes needed in the denylist to be safe from all the known attack vectors, today.
全局更改 ObjectInputStream 只适用于已知恶意类型的黑名单,因为无法知道所有应用程序期望反序列化的类。幸运的是,为了安全地避免所有已知的攻击向量,今天需要的黑名单类非常少。
It's inevitable that more "gadget" classes will be discovered that can be abused. However, there is an incredible amount of vulnerable software exposed today, in need of a fix. In some cases, "fixing" the vulnerability may involve re-architecting messaging systems and breaking backwards compatibility as developers move towards not accepting serialized objects.
不可避免地会发现更多可以被滥用的 "gadget" 类。然而,今天暴露的易受攻击的软件数量惊人,需要修复。在某些情况下,"修复" 漏洞可能涉及重新架构消息系统,并在开发者转向不接受序列化对象时破坏向后兼容性。
To enable these agents, simply add a new JVM parameter:
要启用这些代理,只需添加一个新的 JVM 参数:
-javaagent:name-of-agent.jar
Agents taking this approach have been released by various community members:
采用此方法的代理已由各种社区成员发布:
- rO0 by Contrast Security) (由 Contrast Security 提供 rO0)
A similar, but less scalable approach would be to manually patch and bootstrap your JVM's ObjectInputStream. Guidance on this approach is available here.
类似的方法可能需要手动修补和引导你的 JVM 的 ObjectInputStream,关于这种方法的信息可以在这里找到。
Other Deserialization Libraries and Formats / 其他反序列化库和格式¶
While the advice above is focused on Java's Serializable format, there are a number of other libraries that use other formats for deserialization. Many of these libraries may have similar security issues if not configured correctly. This section lists some of these libraries and recommended configuration options to avoid security issues when deserializing untrusted data:
虽然上面的建议主要关注Java 的 Serializable 格式,但还有许多其他库使用不同的格式进行反序列化。如果不正确配置,这些库中许多可能存在类似的安全问题。本节列出了这些库以及推荐的配置选项,以避免在反序列化不受信任的数据时出现安全问题:
Can be used safely with default configuration:
默认配置下可安全使用:
The following libraries can be used safely with default configuration:
以下库可以在默认配置下安全使用:
- fastjson2 (JSON) - can be used safely as long as
中文:fastjson2 (JSON) - 只要 the autotype option is not turned on
未开启autotype选项
- jackson-databind (JSON) - can be used safely as long
中文:jackson-databind (JSON) - 只要
as polymorphism is not used (see blog post)
因为未使用多态(参见博客文章)
- Kryo v5.0.0+ (custom format) - can be used safely
中文:Kryo v5.0.0+ (自定义格式) - 可以安全使用
as long as class registration is not turned off (see documentation
and this issue)
只要没有关闭类注册(参见文档和此问题)
- YamlBeans v1.16+ (YAML) - can be used safely
中文:YamlBeans v1.16+ (YAML) - 可以安全使用
as long as the UnsafeYamlConfig class isn't used (see this commit)
只要不使用 UnsafeYamlConfig 类(参见此提交)
- NOTE: because these versions are not available in Maven Central,
中文:注意:因为这些版本不在 Maven Central 中可用,
a fork exists) (存在一个分支版本) that can be used instead.
- XStream v1.4.17+* (JSON and XML) - can be used safely
as long as the allowlist and other security controls are not relaxed (see documentation)
只要不放宽允许列表和其他安全控制措施(参见文档)
Requires configuration before can be used safely:
在使用前需要配置:
The following libraries require configuration options to be set before they can be used safely:
以下库在使用前需要设置配置选项才能安全使用:
- fastjson v1.2.68+ (JSON) - cannot be used safely unless the safemode option is turned on, which disables deserialization of any class (see documentation). Previous versions are not safe.
safemode 选项被开启,这会禁用任何类的反序列化(参见文档)。之前的版本不安全。 - json-io (JSON) - cannot be used safely since the use of @type property in JSON allows deserialization of any class. Can only be used safely in following situations:
JSON 允许反序列化任何类。只有在以下情况下才能安全使用: - In non-typed mode using the JsonReader.USE_MAPS setting which turns off generic object deserialization - With a custom deserializer) (使用自定义反序列化器) controlling which classes get deserialized - Kryo < v5.0.0 (custom format) - cannot be used safely unless class registration is turned on, which disables deserialization of any class (see documentation and this issue)
该反序列化器禁用任何类的反序列化(参见文档和此问题) - NOTE: other wrappers exist around Kryo such as Chill, which may also have class registration not required by default regardless of the underlying version of Kryo being used
默认情况下无需,无论使用的Kryo版本如何 - SnakeYAML (YAML) - cannot be used safely unless the org.yaml.snakeyaml.constructor.SafeConstructor* class is used, which disables deserialization of any class (see docs)
使用org.yaml.snakeyaml.constructor.SafeConstructor类,该类禁用任何类的反序列化(参见文档)
Cannot be used safely:
无法安全使用:
The following libraries are either no longer maintained or cannot be used safely with untrusted input:
以下库要么不再维护,或者无法与不受信任的输入安全使用:
- Castor (XML) - appears to be abandoned with no commits since 2016
- fastjson < v1.2.68 (JSON) - these versions allows deserialization of any class
中文:fastjson < v1.2.68 (JSON) - 这些版本允许反序列化任何类 (see documentation)
(参见文档)
- XMLDecoder in the JDK (XML) - "close to impossible to securely deserialize Java objects in this format from untrusted inputs"
中文:JDK 中的 XMLDecoder (XML) - "在不受信任的输入中安全地反序列化 Java 对象几乎是不可能的"**
("Red Hat Defensive Coding Guide", end of section 2.6.5)
("Red Hat 防御性编码指南", 2.6.5节结束)
- XStream < v1.4.17 (JSON and XML) - these versions allows deserialization of any class (see documentation)
中文:XStream < v1.4.17 (JSON 和 XML) - 这些版本允许反序列化任何类(见 文档)
- YamlBeans < v1.16 (YAML) - these versions allows deserialization of any class
中文:YamlBeans < v1.16 (YAML) - 这些版本允许反序列化任何类
(see this document
(参见此文档
.Net CSharp¶
Clear-box Review / 明盒审查¶
Search the source code for the following terms:
在源代码中搜索以下术语:
TypeNameHandlingJavaScriptTypeResolver
Look for any serializers where the type is set by a user controlled variable.
查找任何由用户控制的变量设置类型的序列化程序。
Opaque-box Review / 暗盒审查¶
Search for the following base64 encoded content that starts with:
搜索以下以以下base64编码内容开头的以下内容:
AAEAAAD/////
Search for content with the following text:
搜索以下文本内容:
TypeObject$type:
General Precautions / 一般预防措施¶
Microsoft has stated that the BinaryFormatter type is dangerous and cannot be secured. As such, it should not be used. Full details are in the BinaryFormatter security guide.
微软已声明BinaryFormatter类型是危险的,无法保证安全。因此,不应使用它。详细信息请参阅BinaryFormatter安全指南。
Don't allow the datastream to define the type of object that the stream will be deserialized to. You can prevent this by for example using the DataContractSerializer or XmlSerializer if at all possible.
不要允许数据流定义流将被反序列化为的对象类型。例如,您可以通过使用DataContractSerializer或XmlSerializer来防止这种情况,如果可能的话。
Where JSON.Net is being used make sure the TypeNameHandling is only set to None.
当使用JSON.Net时,请确保TypeNameHandling仅设置为None。
TypeNameHandling = TypeNameHandling.None
If JavaScriptSerializer is to be used then do not use it with a JavaScriptTypeResolver.
如果必须使用JavaScriptSerializer,则不要与JavaScriptTypeResolver一起使用。
If you must deserialize data streams that define their own type, then restrict the types that are allowed to be deserialized. One should be aware that this is still risky as many native .Net types potentially dangerous in themselves. e.g.
如果您必须反序列化定义其自身类型的流数据,则限制允许反序列化的类型。应该意识到这仍然是有风险的,因为许多本机.Net类型本身可能就具有潜在的危险性。例如,
System.IO.FileInfo
FileInfo objects that reference files actually on the server can when deserialized, change the properties of those files e.g. to read-only, creating a potential denial of service attack.
FileInfo对象引用服务器上实际文件,在反序列化时可能会更改这些文件的属性,例如设置为只读,从而创建潜在的拒绝服务攻击。
Even if you have limited the types that can be deserialized remember that some types have properties that are risky. System.ComponentModel.DataAnnotations.ValidationException, for example has a property Value of type Object. if this type is the type allowed for deserialization then an attacker can set the Value property to any object type they choose.
即使您限制了可以反序列化的类型,也要记住某些类型具有风险属性。例如,System.ComponentModel.DataAnnotations.ValidationException具有类型为Object的Value属性。如果此类型允许用于反序列化,则攻击者可以将Value属性设置为任何他们选择的对象类型。
Attackers should be prevented from steering the type that will be instantiated. If this is possible then even DataContractSerializer or XmlSerializer can be subverted e.g.
应阻止攻击者引导将被实例化的类型。如果这可行,那么即使是DataContractSerializer或XmlSerializer也可能被绕过,例如:
// Action below is dangerous if the attacker can change the data in the database
var typename = GetTransactionTypeFromDatabase();
var serializer = new DataContractJsonSerializer(Type.GetType(typename));
var obj = serializer.ReadObject(ms);
Execution can occur within certain .Net types during deserialization. Creating a control such as the one shown below is ineffective.
反序列化过程中,某些.Net类型可能会执行操作。创建如下所示的控件是无效的。
var suspectObject = myBinaryFormatter.Deserialize(untrustedData);
//Check below is too late! Execution may have already occurred.
if (suspectObject is SomeDangerousObjectType)
{
//generate warnings and dispose of suspectObject
}
For JSON.Net it is possible to create a safer form of allow-list control using a custom SerializationBinder.
对于JSON.Net,可以使用自定义SerializationBinder创建一种更安全的允许列表控制形式。
Try to keep up-to-date on known .Net insecure deserialization gadgets and pay special attention where such types can be created by your deserialization processes. A deserializer can only instantiate types that it knows about.
尽量了解已知的.Net不安全反序列化工具,并特别注意这些类型是否可以通过您的反序列化过程创建。反序列化器只能实例化它所知道的类型。
Try to keep any code that might create potential gadgets separate from any code that has internet connectivity. As an example System.Windows.Data.ObjectDataProvider used in WPF applications is a known gadget that allows arbitrary method invocation. It would be risky to have this a reference to this assembly in a REST service project that deserializes untrusted data.
尽量将可能创建潜在工具的任何代码与任何具有互联网连接的代码分开。例如,System.Windows.Data.ObjectDataProvider是WPF应用程序中已知的一种工具,它允许任意方法调用。在反序列化不受信任数据的REST服务项目中引用此程序集是有风险的。
Known .NET RCE Gadgets / 已知的.NET RCE工具¶
System.Configuration.Install.AssemblyInstallerSystem.Activities.Presentation.WorkflowDesignerSystem.Windows.ResourceDictionarySystem.Windows.Data.ObjectDataProviderSystem.Windows.Forms.BindingSourceMicrosoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProviderSystem.Data.DataViewManager, System.Xml.XmlDocument/XmlDataDocumentSystem.Management.Automation.PSObject
Language-Agnostic Methods for Deserializing Safely / 用于安全反序列化的语言无关方法¶
Using Alternative Data Formats / 使用替代数据格式¶
A great reduction of risk is achieved by avoiding native (de)serialization formats. By switching to a pure data format like JSON or XML, you lessen the chance of custom deserialization logic being repurposed towards malicious ends.
通过避免使用本地(反)序列化格式,可以实现风险的大幅降低。通过切换到纯数据格式,如JSON或XML,可以减少自定义反序列化逻辑被用于恶意目的的可能性。
Many applications rely on a data-transfer object pattern that involves creating a separate domain of objects for the explicit purpose data transfer. Of course, it's still possible that the application will make security mistakes after a pure data object is parsed.
许多应用程序依赖于一个数据传输对象模式,该模式涉及创建一个独立的对象域,专门用于数据传输。当然,应用程序在解析纯数据对象后仍然可能犯下安全错误。
Only Deserialize Signed Data / 仅反序列化已签名数据¶
If the application knows before deserialization which messages will need to be processed, they could sign them as part of the serialization process. The application could then to choose not to deserialize any message which didn't have an authenticated signature.
如果应用程序在反序列化之前就知道哪些消息需要被处理,它们可以在序列化过程中对它们进行签名。然后,应用程序可以选择不反序列化任何未经过认证签名的消息。
Mitigation Tools/Libraries¶
- Java secure deserialization library) (Java安全反序列化库)
- SWAT - tool for creating allowlists) (SWAT - 创建允许列表的工具)
- NotSoSerial
Detection Tools / 检测工具¶
- Java deserialization cheat sheet aimed at pen testers) (面向渗透测试员的Java反序列化作弊表)
- A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization.) (用于生成利用不安全Java对象反序列化的有效载荷的PoC工具)
- Java De-serialization toolkits) (Java反序列化工具包)
- Java de-serialization tool) (Java反序列化工具)
- .Net payload generator) (.Net有效载荷生成器)
- Burp Suite extension) (Burp Suite扩展)
- Java secure deserialization library) (Java安全反序列化库)
- Serianalyzer is a static bytecode analyzer for deserialization) (Serianalyzer是一款用于反序列化的静态字节码分析器)
- Payload generator) (载荷生成器)
- Android Java Deserialization Vulnerability Tester) (Android Java 反序列化漏洞测试器)
- Burp Suite Extension
中文:Burp Suite 扩展- JavaSerialKiller
- Java Deserialization Scanner) (Java 反序列化扫描器)
- Burp-ysoserial
- SuperSerial) (超级序列)
- SuperSerial-Active) (超级序列-主动)
References / 参考¶
- Oracle Java 17: Serialization Filtering) (Oracle Java 17: 序列化过滤)
- Microsoft: Deserialization Risks in Use of BinaryFormatter and Related Types) (Microsoft: 使用 BinaryFormatter 和相关类型时的反序列化风险)
- Python: pickle Security Warning) (Python: pickle 安全警告)