解決方法:
// 用到的工具類:
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執行反序列化時要強制實施的安全控制,從而保
護應用程序代碼以及庫和框架代碼免受此類攻擊。