Tip To Developers … Avoid Using Immutable Types for Passwords and Sensitive User Data

I spend a good deal of my time reviewing the security of code these days, and recent I asked a developer why they had used strings to…

Tip To Developers … Avoid Using Immutable Types for Passwords and Sensitive User Data

Here 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”. Etc.

Mutable and immutable

Our 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:

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:  33280368
ID String2: 33280752
Strings are not the same
ID String1: 33280368
ID String2: 33280368
Strings are the same

The pre-defined mutable objects are list, dict, set and byte array. Now if we try a list object:

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: 32508424
ID String2: 32483688
Lists are not the same

The key factor of immutable 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:

and where both list1 and list3 will change when we allocate a new value to the first element of list3:

List 1: 34802184
List 3: 34802184
List 1: [‘dog’, ‘lion’, ‘cat’]
List 3: [‘dog’, ‘lion’, ‘cat’]

Whereas if we do this for immutable objects:

g=3
h=g
h=4
print “ID(g): “,id(g)
print “ID(h): “,id(h)
print “g: “,g
print “h: “,h

and which gives:

ID(g): 1866272
ID(h: 1866260
g: 3
h: 4

Passwords, keys and sensitive data

And 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 x
rtn=getpass()
print “Returned: “,rtn
rtn[:] = ‘’
print “After erase:”,rtn

And a run shows that we have erased the memory for the password object:

Returned: qwerty
After erase:

Conclusions

In 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.

If you want to use a language that properly does immutability, try Rust here.