Tip To Developers … Avoid Using Immutable Types for Passwords and Sensitive User DataProf Bill Buchanan OBEBlockedUnblockFollowFollowingFeb 17Here is a discussion with a developer on their code …“Why have you stored the passwords as string?”, “Passwords are just strings.
What’s the problem?”, “Well, strings are immutable objects”.
“But I allocate a null string after I use it, so it’s okay!”, “But that doesn’t actually erase it from memory”.
“Yes, it does”, “No, it doesn’t”.
Mutable and immutableOur software world has moved to use objects, and these objects can be mutable or immutable.
In Python, the predefined types such as int, float, bool, and str are immutable, whereas user-defined classes which are defined as mutable.
When an object is created it is assigned a unique object identifier and is defined by a given type.
There are then no changes allowed for an immutable object, but a mutable object can have its state changed.
In Python, we can determine the memory location of an object by using the id() function.
In the following, we allocate two strings, and then determine their memory location:str1="RSA"str2="ECC"g=5print "ID String1: ",id(str1)print "ID String2: ",id(str2)if (str1 is str2): print "Strings are the type"else: print "Strings are not the same"str1="RSA"str2="RSA"g=5print "ID String1: ",id(str1)print "ID String2: ",id(str2)if (str1 is str2): print "Strings are the type"else: print "Strings are not the same"The result looks rather strange, as when str1 is not equal to str2, they are stored at different memory locations, but they are stored at the same place they are equal:ID String1: 33280368ID String2: 33280752Strings are not the sameID String1: 33280368ID String2: 33280368Strings are the typeThe pre-defined mutable objects are list, dict, set and byte array.
Now if we try a list object:list1=['elephant','lion','cat']list2=['elephant','lion','cat']print "ID list1: ",id(list1)print "ID list2: ",id(list2)if (list1 is list2): print "Lists are the type"else: print "Lists are not the same"We now see that the memory locations are different and that the objects are not the same (even though they have the same values):ID String1: 32508424ID String2: 32483688Lists are not the sameThe key factor of mutable objects is that they cannot be changed once they have been created whereas mutable objects can change both their state or contents.
A mutable object is thus a real thing in memory, and we can allocate other objects to the target object.
We can see this in the following:list1=['elephant','lion','cat']list3=list1list3='dog'print "List 1: ",id(list3)print "List 3: ",id(list3)print "List 1: ",list1print "List 3: ",list3and where both list1 and list3 will change when we allocate a new value to the first element of list3:List 1: 34802184List 3: 34802184List 1: [‘dog’, ‘lion’, ‘cat’]List 3: [‘dog’, ‘lion’, ‘cat’]Whereas if we do this for immutable objects:g=3h=gh=4print “ID(g): “,id(g)print “ID(h): “,id(h)print “g: “,gprint “h: “,hand which gives:ID(g): 1866272ID(h: 1866260g: 3h: 4Passwords, keys and sensitive dataAnd so the problem with using passwords, encryption keys, and other sensitive data is that we can’t actually erase the memory that has been allocated to an immutable object.
Once it has been allocated, we must wait for the garbage collector to come along and — hopefully — erase the password from memory.
But if we use a byte array we can easily erase the contents of the object:def getpass(): password=’qwerty’ x=bytearray(password) return xrtn=getpass()print “Returned: “,rtnrtn[:] = ‘’print “After erase:”,rtnAnd a run shows that we have erased the memory for the password object:Returned: qwertyAfter erase:ConclusionsIn secure code, never use immutable objects to store sensitive data.
If possible, you should use byte arrays or lists, as these can be easily erased after use.
If your development team is thus processing sensitive information, and do not know the difference between immutable and mutable objects, you might want to send them on a training course.
.. More details