首页 > 解决方案 > 对 SerializationProxy 的字节流攻击:它更安全吗?

问题描述

岗位结构

  1. 设想
  2. 问题
  3. 代码和输出
  4. 附加信息/评论

1. 场景 鉴于我可以编辑(私有嵌套)SerializedProxy(属于 Serializable 类)的序列化字节流以打破 SerializedProxy 本身的不变量,因此我可以更改正在反序列化的实例。

在我可以访问 SerializedProxy 类的序列化形式的这种情况下,对正在序列化的类的字节流攻击同样容易,而无需在 readResolve() 中强制执行不变量。

2. 问题

SerializationProxy 方法的所谓安全性——wrt 字节流攻击——是否纯粹基于序列化形式的内容或 SerializedProxy 的源代码总是对攻击者不可用的假设?如果没有,我是否误解或错过了这里的某些实施部分?

3.Code (注意:Serializer是一个将序列化对象写入文件的util类。)

3.1使用值 5 序列化代理

    import java.io.Serializable;
    import java.io.InvalidObjectException;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    public class SerializationProxyTest implements Serializable
    {
        final int id;

        private SerializationProxyTest(int val)
        {
            id = val;
        }

        private void writeObject() throws InvalidObjectException, IOException
        {
            throw new InvalidObjectException("Invalid object called for Serialization: proxy not found.");
        }


        private Object writeReplace()
        {
            System.out.println("writeReplace 1 ");
            return new SerializationProxy(this);

        }

        private static class SerializationProxy implements Serializable
        {
            final int id;

            SerializationProxy(SerializationProxyTest obj)
            {
                this.id = obj.id;
            }

            /* private void writeObject(ObjectOutputStream oos) throws IOException
            {

                oos.defaultWriteObject();

            } */

            private Object readResolve()
            {
                System.out.println("readResolve step 1 ");
                return new SerializationProxyTest(this.id);
                // return "Something Else!";

            }
        }

        public static void main(String[] args) throws IOException, ClassNotFoundException
        {

            Serializer.serializeObject(new SerializationProxyTest(5));

            SerializationProxyTest spt = (SerializationProxyTest) Serializer.deserializeObject("/home/code/java/serialized_proxy_class.ser");

            System.out.println("stored variable is:  " + spt.id);
        }
    }

3.1 输出:

   [java]$ java SerializationProxyTest
            writeReplace 1 
            readResolve 1 
            object is: SerializationProxyTest@4eec7777
            stored variable is:  5

ACED 0005 7372 0029 5365 7269 616C 697A 6174 6174 696F 6E50 726F 7879 5465 7374 24574 24572 6572 6961 6C691 6C69 7A69 7A61 7A61 7469 6F6E

3.2更改序列化的 SerializedProxy 以将变量的值更改为 6

ACED 0005 7372 0029 5365 7269 616C 697A 6174 6174 696F 6E50 726F 7879 5465 7374 24574 24572 6961 6C691 6C69 7A69 7A61 7A61 7469 6F6E

3.3通过反序列化改变后的 SerializedProxy 来初始化 Serializable 类:SerializationProxyTest 类初始化为 6 而不是 5。

                SerializationProxyTest spt = (SerializationProxyTest) Serializer.deserializeObject("/home/code/java/serialized_proxy_class.ser");

            System.out.println("stored variable is:  " + spt.id);

        [java]$ java SerializationProxyTest
    writeReplace 1 
    readResolve 1 
    object is: SerializationProxyTest@4eec7777
    stored variable is:  6

4.附加信息/评论:SerializedProxy 方法的某些固有“安全性”的假设只是阅读“有效 Java”时产生的好奇心。这里所做的另一个假设是,即使不知道类结构,攻击者也可以通过反复试验对字节流进行有效更改。

标签: javasecurityserialization

解决方案


反序列化时,串行代理必须强制执行与构造函数相同的不变量(或者,如果您采用该路线,则为静态创建方法)。这通常是通过串行代理使用公共构造函数(或方法)来创建真实对象来实现的。

在问题的代码中,始终为 5 的不变量id位于静态创建方法 ( main) 中。串行代理代码不使用它。

注意:你SerializationProxyTest是可子类化的。Java 字节码不需要类具有构造函数,因此基类没有必要具有可访问的构造函数。通常,您的类的任何非最终公共或受保护方法都可能是可重写的。

另请注意,第 3 版 Effective Java 的序列化章节中有更正 - 不要使用早期版本。


推荐阅读