...
In this noncompliant code example, security manager checks are used within the constructor but are omitted from the writeObject()
and readObject()
methods that are used in the serialization-deserialization process. This allows untrusted code to maliciously create instances of the class.
We assume that AccessDeniedException
and InvalidInputException
are both security exceptions, and hence require no checking.
Code Block | ||
---|---|---|
| ||
public final class CreditCard implements Serializable { // Private internal state private String credit_card; private static final String DEFAULT = "DEFAULT"; void performSecurityManagerCheck() throws AccessDeniedException { // ... } void validateInput(String newCC) throws InvalidInputException { // ... } public CreditCard() throws AccessDeniedException { performSecurityManagerCheck(); // Initialize credit_card to default value credit_card = DEFAULT; } // Allows callers to retrieve internal state String getValue() { return credit_card; } // Allows callers to modify (private) internal state public void changeCC(String newCC) throws InvalidInputException { if (credit_card.equals(newCC)) { // No change return; } else { performSecurityManagerCheck(); validateInput(newCC); credit_card = newCC; } } // writeObject() correctly enforces checks during serialization private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(credit_card); } // readObject() correctly enforces checks during deserialization private void readObject(ObjectInputStream in) throws IOException, InvalidInputException { in.defaultReadObject(); // If the deserialized name does not match the default value normally // created at construction time, duplicate the checks if (!DEFAULT.equals(credit_card)) { validateInput(credit_card); } } // Allows callers to retrieve internal state String getValue() { return credit_card; } // writeObject() correctly enforces checks during serialization private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(credit_card); } } |
Compliant Solution
This compliant solution implements the required security manager checks in all constructors and methods that can either modify or retrieve internal state. Consequently, an attacker cannot create a modified instance of the object (using deserialization) or read the serialized byte stream to uncover sensitive serialized data.
Code Block | ||
---|---|---|
| ||
public final class SecureCreditCardCreditCard implements Serializable { // Private... internalall state methods the privatesame String credit_card; private static final String DEFAULT = "DEFAULT";except the following: void performSecurityManagerCheck() throws AccessDeniedException { // ... } void validateInput(String newCC) throws InvalidInputException // Allows callers to retrieve internal state public String getValue() { // ... Check permission } to public SecureCreditCard() throws AccessDeniedException {get value performSecurityManagerCheck(); // Initialize credit_card to default value credit_card = DEFAULTreturn somePublicValue; } //allows callers to modify (private) internal state public void changeCC(String newCC) throws AccessDeniedException, InvalidInputException { if (credit_card.equals(newCC)) { // No change return; } else { // Check permissions to modify credit_card performSecurityManagerCheck(); validateInput(newCC); credit_card = newCC; } } // readObjectwriteObject() correctly enforces checks during deserializationserialization private void readObjectwriteObject(ObjectInputStreamObjectOutputStream inout) throws IOException { in.defaultReadObject(); // IfDuplicate thecheck deserialized name does not match the default value normally // created at construction time, duplicate the checks if (!DEFAULT.equals(credit_card)) { from getValue() performSecurityManagerCheck(); validateInputout.writeObject(credit_card); } } // AllowsreadObject() callerscorrectly toenforces retrievechecks internalduring statedeserialization publicprivate Stringvoid getValuereadObject(ObjectInputStream in) { throws // Check permission to get valueIOException { performSecurityManagerCheckin.defaultReadObject(); return somePublicValue; } // writeObject() correctly enforces checks during serialization private void writeObject(ObjectOutputStream out) throws IOException { // Duplicate check from getValue()// If the deserialized name does not match the default value normally // created at construction time, duplicate the checks if (!DEFAULT.equals(credit_card)) { performSecurityManagerCheck(); out.writeObjectvalidateInput(credit_card); } } } |
Refer to guideline SEC08-J. Protect sensitive operations with security manager checks to learn about implementing the performSecurityManagerCheck()
method. As with guideline SER04-J. Validate deserialized objects, it is important to protect against the finalizer attack.
...