Java 序列化代理上的字节流攻击:安全吗?

Java 序列化代理上的字节流攻击:安全吗?,java,security,serialization,Java,Security,Serialization,职位结构: 情景 问题: 代码和输出 其他信息/评论 1。 情景 假设我可以编辑(可序列化类的)SerializedProxy(私有嵌套)的序列化字节流,以破坏SerializedProxy本身的不变量,因此,我可以更改正在反序列化的实例 在这种情况下,我可以访问SerializedProxy类的序列化形式,在不强制readResolve()中的不变量的情况下,对被序列化的类的字节流攻击同样容易 2。问题 SerializationProxy方法(wrt字节流攻击)的安全性是否纯粹基于以下假设:

职位结构

  • 情景
  • 问题:
  • 代码和输出
  • 其他信息/评论
  • 1。 情景 假设我可以编辑(可序列化类的)SerializedProxy(私有嵌套)的序列化字节流,以破坏SerializedProxy本身的不变量,因此,我可以更改正在反序列化的实例

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

    2。问题

    SerializationProxy方法(wrt字节流攻击)的安全性是否纯粹基于以下假设:序列化形式的内容或SerializedProxy的源代码始终不可供攻击者使用?如果没有,我是否误解或遗漏了此处的某些实施内容

    3.代码 (注意:序列化程序是一个将序列化对象写入文件的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产出:

    aced 0005 7372 0029 5365 7269 616c 697a 6174 696f 6e50 726f 7879 5465 7374 2453 6572 6961 6c69 7a61 7469 6f6e 5072 6f78 793b 8ab7 89f9 dd6d aa02 0001 4900 0269 6478 7000 00005

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

        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);
            }
        }
    
    aced 0005 7372 0029 5365 7269 616c 697a 6174 696f 6e50 726f 7879 5465 7374 2453 6572 6961 6c69 7a61 7469 6f6e 5072 6f78 793b 8ab7 89f9 dd6d aa02 0001 4900 0269 6478 7000 00006

    3.3通过反序列化来初始化可序列化类修改后的SerializedProxy: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”后产生的好奇心。这里提出的另一个假设是,攻击者可以通过反复试验,在不知道类结构的情况下,对字节流进行有效更改。

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

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

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


    还要注意的是,第三版有效Java的序列化章节中有一些更正-不要使用早期版本。

    代理不应该为它正在代理的类保留不变量吗?例如,在我上面的问题中,我希望SerializationProxy建立与SerializationProxyTest实例相同的不变量,该实例在main方法中以id=5创建。请忽略我之前的评论:重新阅读您的答案可以澄清问题。另外,感谢您提供有关上一版本已过时的信息。