...
Code Block | ||||
---|---|---|---|---|
| ||||
import java.io.*; import java.util.*; class WhitelistedObjectInputStream extends ObjectInputStream { public Set whitelist; public WhitelistedObjectInputStream(InputStream inputStream, Set wl) throws IOException { super(inputStream); whitelist = wl; } @Override protected Class<?> resolveClass(ObjectStreamClass cls) throws IOException, ClassNotFoundException { if (!whitelist.contains(cls.getName())) { throw new InvalidClassException("Unexpected serialized class", cls.getName()); } return super.resolveClass(cls); } } class DeserializeExample { private static Object deserialize(byte[] buffer) throws IOException, ClassNotFoundException { Object ret = null; Set whitelist = new HashSet<String>(Arrays.asList(new String[]{"GoodClass1","GoodClass2"})); try (ByteArrayInputStream bais = new ByteArrayInputStream(buffer)) { try (WhitelistedObjectInputStream ois = new WhitelistedObjectInputStream(bais, whitelist)) { ret = ois.readObject(); } } return ret; } } |
It might appear that the above compliant solution violates Rule OBJ09-J. Compare classes and not class names. However, the security issue addressed by OBJ-09J is applicable only when comparing the class of an object that might have been loaded by a foreign ClassLoader
, i.e., an object x for which it cannot be guaranteed that x.getClass()==Class.forName(x.getClass().getName())
. In WhitelistedObjectInputStream.resolveClass
(which is the method that does the comparison of class names), a check could be added to verify that the return value (let's call it "ret
") is such that ret == Class.forName(ret.getName())
, but this check would always succeed, so it is pointless to add.
(On a somewhat related point, it may be noted that ObjectInputStream.resolveClass
compares the serialVersionUID
from the serialized data to the serialVersionUID
of the Class object that it is going to return; if there is a mismatch, it throws an exception.)
Exceptions
SER12-EX0: Serialized data from a trusted input source does not require validation, provided that the code clearly documents that it relies on the input source being trustworthy. For example, if a library is being audited, a routine of that library may have a documented precondition that its callers pre-validate any passed-in serialized data or confirm the input source as trustworthy.
...