...
This noncompliant code example is capable of being serialized and transferred across different business tiers. Unfortunately, there are no safeguards against byte stream manipulation attacks while the binary data is in transit. Likewise, anyone can reverse engineer the stream data from its hexadecimal notation to unravel reveal the data in the HashMap
containing sensitive social security numbers.
Code Block | ||
---|---|---|
| ||
class SimpleObject<ESerializableMap<K,V> implements Serializable { final static long serialVersionUID = -2648720192864531932L; private HashMap<EHashMap<K,V> ssnMapmap; public SimpleObjectSerializableMap() { ssnMapmap = new HashMap<EHashMap<K,V>(); } public Object getdatagetData(EK key) { return ssnMapmap.get(key); } public void setData(EK key, V data) { ssnMapmap.put(key, data); } } |
If the data in the map is considered sensitive, this example will also violate SER03-J. Do not serialize unencrypted, sensitive data.
Compliant Solution
To provide message confidentiality, use the javax.crypto.SealedObject
class. This class encapsulates a serialized object and encrypts (or seals) it. A strong cryptographic algorithm that uses a secure cryptographic key and padding scheme must be employed to initialize the Cipher
object parameter. The seal
and unseal
utility methods provide the encryption and decryption facilities respectively.
In addition, use the sign()
and unsign()
utility methods java.security.SignedObject
class to sign the object, when the integrity of the object is to be ensured. The two new arguments passed in to the SignedObject()
method to sign the object are Signature
and a private key derived from a KeyPair
object. To verify the signature, a PublicKey
as well as a Signature
argument is passed to the SignedObject.verify()
method. This enables the code to comply with SEC17-J. Create and sign a SignedObject before creating a SealedObject.
Code Block | ||
---|---|---|
| ||
class SignSealUtility<ESerializableMap<K,V> implements Serializable { final// staticother longfields serialVersionUID = 2648720192864531932L; private HashMap<E,V> ssnMap; private SealedObject sealedSsnMap;and methods... private SignedObject signedSsnMapsignedMap; public void SignSealUtilitysign()Signature { sig, ssnMap = new HashMap<E,V>();PrivateKey key) } publicthrows void seal(Cipher cipher) throws ExceptionIOException, GeneralSecurityException { sealedSsnMapsignedMap = new SealedObject(ssnMapSignedObject( map, key, ciphersig); // Now set the Map to null so that original data does not remain in cleartextmap = null; } public void unsign(Signature sig, PublicKey key) ssnMap = null; throws IOException, GeneralSecurityException, ClassNotFoundException { } public void unseal(Cipher cipher) throws Exception { if (signedMap.verify(key, sig)) { ssnMapmap = (HashMap<EHashMap<K,V>)sealedSsnMap signedMap.getObject(cipher)); signedMap = null; } } private SealedObject sealedMap; public void sign(Signature sig, PrivateKey key) throws Exceptionseal(Cipher cipher) throws IOException, IllegalBlockSizeException { signedSsnMapsealedMap = new SignedObjectSealedObject(ssnMapsignedMap, key, sigcipher); ssnMap// =Now null; set the } Map to publicnull voidso unsign(Signature sig, PublicKey key) throws Exception { if(signedSsnMap.verify(key, sig)) {that original data does not remain in cleartext ssnMapsignedMap = (HashMap<E,V>)signedSsnMap.getObject(); }null; } public Objectvoid getdataunseal(ECipher keycipher) throws Exception { throws IOException, GeneralSecurityException, return ssnMap.get(key);ClassNotFoundException { } signedMap public= void setData(E key, V data) throws Exception { ssnMap.put(key, data)(SignedObject) sealedMap.getObject(cipher); sealedMap = null; } } |
Finally, refrain from signing encrypted (sealed) data. (See guideline SEC17-J. Create and sign a SignedObject before creating a SealedObject.)
...