Java 序列化的使用是一个严重的问题吗?

Java 序列化的使用是一个严重的问题吗?,java,security,serialization,Java,Security,Serialization,我已经为一个聊天程序创建了一个类消息,其中包含关于特定消息的所有信息。消息实例在服务器和客户端之间来回发送。我正在使用序列化(ObjectInputStream/ObjectOutputStream)来交换这些消息 我无法控制序列化和反序列化的过程。对我来说,最大的问题是,如果某个攻击者想要发送一条非常沉重的消息(比如说几GB),我没有办法避免它,我可能会遇到一些严重的内存问题。这可能用于拒绝服务,这是严重的 我看了很多关于序列化及其安全问题的不同主题,但没有人提到如何避免这个琐碎的问题。我希望

我已经为一个聊天程序创建了一个类消息,其中包含关于特定消息的所有信息。消息实例在服务器和客户端之间来回发送。我正在使用序列化(ObjectInputStream/ObjectOutputStream)来交换这些消息

我无法控制序列化和反序列化的过程。对我来说,最大的问题是,如果某个攻击者想要发送一条非常沉重的消息(比如说几GB),我没有办法避免它,我可能会遇到一些严重的内存问题。这可能用于拒绝服务,这是严重的

我看了很多关于序列化及其安全问题的不同主题,但没有人提到如何避免这个琐碎的问题。我希望能够使用缓冲区以字节数组的形式检索数据,以便随时停止读取。但是我找不到任何方法来实现序列化问题:我应该这样处理吗

此外,欢迎对序列化的安全问题发表任何意见。我听说您可以在可序列化类的实例中注入恶意代码,但既然该类在客户端和服务器上的定义必须相同,那么这怎么可能呢


提前感谢您的帮助

如果FilterInputStream从底层流读取的数据超过X字节,为什么不编写FilterInputStream()来引发异常

有一种方法可用于替换此页面上对readObject的调用:

/**
*替换Java中内置的不安全ObjectInputStream.readObject()方法的方法。这种方法
*检查以确保引用的类是安全的,对象的数量限制在合理的范围内,
*并且字节数被限制在一个合理的数目内。返回的对象也被强制转换为
*指定的类型。
*
*@param type类,表示预期返回的对象类型
*@param safeClasses正在读取的序列化对象中允许的类的列表
*@param maxObjects long表示正在读取的序列化对象内部允许的最大对象数
*@param maxBytes long表示允许从InputStream读取的最大字节数
*InputStream中的@param包含不受信任的序列化对象
*@return对象从流中读取(强制转换为类型参数的类)
*@抛出异常
*@ClassNotFoundException
*/
@抑制警告(“未选中”)

公共静态安全读取对象(类类型,列表取决于您对安全性的重视程度。仅使用JSON?无法防止硬DDOS,但使用Java序列化确实有许多缺点。您的问题似乎不是真正的序列化。如果您担心人们发送大消息,您应该记录最大消息大小和在客户端API和传输消息的服务器上强制使用它。@chrylis JSON似乎无法解决我的问题,因为我需要设置大小限制以避免接收大文件。KevinKrumwiede:我的问题是如何在服务器上执行此操作?我同意@KevinKrumwiede。是的,序列化漏洞是一个严重的问题,并且uld导致攻击者远程执行代码。请参阅-在反序列化过程开始之前,至少使用HMAC和强键验证接收到的数据。但我使用的是ObjectInputStream,因此我无法计算字节数,因为我必须使用readObject方法。该方法的问题是我需要重复接收消息。Cal每次运行该函数都会重复创建新的OIS,这将导致流标头错误。我曾尝试将FilterInputStream和ObjectInputStream子类化以解决此问题,但问题是字节根本不计数。我可以发送任意大的消息。这根本不起作用。
/**
 * A method to replace the unsafe ObjectInputStream.readObject() method built into Java. This method
 * checks to be sure the classes referenced are safe, the number of objects is limited to something sane,
 * and the number of bytes is limited to a reasonable number. The returned Object is also cast to the
 * specified type.
 *
 * @param type Class representing the object type expected to be returned
 * @param safeClasses List of Classes allowed in serialized object being read
 * @param maxObjects long representing the maximum number of objects allowed inside the serialized object being read
 * @param maxBytes long representing the maximum number of bytes allowed to be read from the InputStream
 * @param in InputStream containing an untrusted serialized object
 * @return Object read from the stream (cast to the Class of the type parameter)
 * @throws IOException
 * @throws ClassNotFoundException
 */

@SuppressWarnings("unchecked")
public static  T safeReadObject(Class<?> type, List<Class<?>> safeClasses, long maxObjects, long maxBytes, InputStream in ) throws IOException, ClassNotFoundException {
    // create an input stream limited to a certain number of bytes
    InputStream lis = new FilterInputStream( in ) {
        private long len = 0;
        public int read() throws IOException {
            int val = super.read();
            if (val != -1) {
                len++;
                checkLength();
            }
            return val;
        }
        public int read(byte[] b, int off, int len) throws IOException {
            int val = super.read(b, off, len);
            if (val > 0) {
                len += val;
                checkLength();
            }
            return val;
        }
        private void checkLength() throws IOException {
            if (len > maxBytes) {
                throw new SecurityException("Security violation: attempt to deserialize too many bytes from stream. Limit is " + maxBytes);
            }
        }
    };
    // create an object input stream that checks classes and limits the number of objects to read
    ObjectInputStream ois = new ObjectInputStream( lis ) {
        private int objCount = 0;
        boolean b = enableResolveObject(true);
        protected Object resolveObject(Object obj) throws IOException {
            if ( objCount++ > maxObjects ) throw new SecurityException( "Security violation: attempt to deserialize too many objects from stream. Limit is " + maxObjects );
            Object object = super.resolveObject(obj);
            return object;
        }
        protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
            Class<?> clazz = super.resolveClass(osc);
            if (
                clazz.isArray() ||
                clazz.equals(type) ||
                clazz.equals(String.class) ||
                Number.class.isAssignableFrom(clazz) ||
                safeClasses.contains(clazz)
            ) return clazz;
            throw new SecurityException("Security violation: attempt to deserialize unauthorized " + clazz);
        }
    };
    // use the protected ObjectInputStream to read object safely and cast to T
    return (T)ois.readObject();
}