Dynamic Code Evaluation Unsafe Deserialization解决方法


 

解决方法:

// 用到的工具类:
public
static Object myReadObject(Class<?> targetClass, List<Class<?>> safeClasses, long maxObjects, long maxBytes, InputStream in) throws ClassNotFoundException, IOException { InputStream lis = null; ObjectInputStream ois = null; Object returnObject = null; try { // create an input stream limited to a certain number of bytes 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); } } }; 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.equals(targetClass) || safeClasses.contains(clazz)) return clazz; throw new SecurityException("Security violation: attempt to deserialize unauthorized " + clazz); } }; if (null != ois) { returnObject = ois.readObject(); } } catch (IOException e) { //异常处理 } finally { safeClose(lis); safeClose(ois); } return returnObject; } public static void safeClose(InputStream is) { if (is != null) { try { is.close(); } catch (IOException e) { //异常处理 } } } // add white list List<Class<?>> safeClasses = Arrays.asList();

              //报错位置红色字体

                ByteSequence content = getContent();
                InputStream is = new ByteArrayInputStream(content);
                if (isCompressed()) {
                    is = new InflaterInputStream(is);
                }
                DataInputStream dataIn = new DataInputStream(is);
                ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn);
                try {
                    object = (Serializable)objIn.readObject();
                ... 
                                         
                                          修改如下,即可解决
                                    👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
                ByteSequence content = getContent();
                InputStream is = new ByteArrayInputStream(content);
                if (isCompressed()) {
                    is = new InflaterInputStream(is);
                }
                //fix issue (Dynamic Code Evaluation: Unsafe Deserialization)
                List<Class<?>> safeClasses=Arrays.asList(Serializable.class); 
                // DataInputStream dataIn = new DataInputStream(is);
                // ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn);
                try {
                    // object = (Serializable)objIn.readObject();
                    object = (Serializable) myReadObject(Serializable.class, safeClasses, 10, 2048, is);
                  ...

  

 

问题描述:

Abstract

在运行时反序列化用户控制的对象流可使攻击者能够在服务器上执行任意代码、滥用应用程序逻辑和/或导致拒绝服务。

Explanation

Java序列化将对象图转换为字节流,这些字节流包含对象本身和从字节流重构它们所需的元数据。开发人员可以创建自定义代码来帮助反序列化Java对象的过程,在这个过程中,
他们可以用不同的对象或代理替换反序列化的对象。定制的反序列化过程在对象重新构建期间进行,然后将对象返回到应用程序并强制转换为预期的类型。当开发人员尝试强制执行
预期类型时,代码可能已经执行。自定义反序列化例程在可序列化类中定义,这些可序列化类需要出现在运行时类路径中,并且不能由攻击者注入,因此这些攻击的可利用性取决于应
用程序环境中可用的类。不幸的是,常见的第三方类甚至JDK类可能会被滥用来耗尽JVM资源、部署恶意文件或运行任意代码。某些协议在传输层的幕后使用Java序列化。RMI和JMX
就是这些协议的示例

示例1:
下面是一个可以公开的RMI接口示例,它包含带有一个或多个参数的方法。远程调用这些方法时,参数将在服务器上反序列化,从而允许攻击者注入恶意对象图。

public interface MyService extends java.rmi.Remote { 
public Object doSomething (Object arg0) throws RemoteException; 
public Object doSomethingElse (Object arg0, Object arg1) throws RemoteException; 
... } 

  

示例2:
JMX MBean还使用Java序列化来传输调用参数。在下面的示例中,MyManagedBean类方法将向客户端公开。

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 
ObjectName name = new ObjectName("com.example:type=MyManagedBean");
MyManagedBean mbean = new MyManagedBean(); mbs.registerMBean(mbean, name);

 

Recommendation

如果可能,请不要在未验证对象流内容的情况下反序列化不受信任的数据。为了验证要反序列化的类,应该使用先行反序列化模式。对象流将首先包含类描述元数据,然后包含其成员
字段的序列化字节。Java序列化过程允许开发人员读取类描述,并决定是继续对象的反序列化还是中止它。为此,需要将java.io.ObjectInputStream子类化,并提供解决方案类
(ObjectStreamClass Desc)方法的自定义实现,其中应该进行类验证和验证。存在易于使用的前瞻性模式的现有实现,
例如Apache Commons IO(org.apache.commons.io.serialization.ValidatingObjectInputStream).。始终使用严格的白名单方法仅反序列化预期类型。不建议使用
黑名单方法,因为攻击者可能会使用许多可用的小工具绕过黑名单。此外,请记住,尽管实现代码执行的某些类是公开的,但可能还有其他类是未知的或未公开的,因此白名单方法将
始终是首选的方法。应该审计白名单中允许的任何类,以确保可以安全地反序列化。当库中发生反序列化时,或框架(例如,当使用JMX、RMI、JMS、HTTP调用器时)上述建议没有用处
,因为它超出了开发人员控制。在这些情况下,您可能希望确保这些协议满足以下要求:-不公开。-使用身
份验证。-使用完整性检查。-使用加密。此外,HPE Security Fortify Runtime提供了每次应用程序从ObjectInputStream执行反序列化时要强制实施的安全控制,从而保
护应用程序代码以及库和框架代码免受此类攻击。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM