Passwords should be wiped from memory #53
Replies: 11 comments 12 replies
-
Thanks for this. Sorry to take so long to reply. Yes, I agree and if there is a future version the String returning getPassword() should be deprecated in favour of one that returns a byte array. |
Beta Was this translation helpful? Give feedback.
-
@danielgrahl Other fields like username, URL, etc. are also stored as Strings. Would it be better to instead store them as byte arrays too, even though they aren't as valuable as a password? |
Beta Was this translation helpful? Give feedback.
-
I think the approach to the question as posed, should be:
A related (and possibly more important) question is what to do about the storage of passwords (and other sensitive fields) in the underlying data storage. As things stand these fields are "inner stream encoded" in the XML meaning they are base64 representation of encrypted values in the XML stream (which is itself encrypted as overall encryption of the database). These fields are decrypted when the database is loaded and are stored in memory as, well, strings. You can see what this looks like, a bit, by doing this: database.save(new StreamFormat.None(), new Credentials.None(), System.out); in the output from this, protected fields are "merely" base 64 encoded, they are not encrypted then base64 encoded when you use There are a few ways one could improve having strings in memory.
As Dominik points out in the reference above, this is all very well till it comes to actually using the passwords, when they will typically be needed as Strings, anyway. I'd welcome discussion. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure this solution is perfectly compliant to protect sensitive data, and I'm not convinced the change of the data structure to represent sensitive information is the right solution. If I have access to the memory as an attacker, I can retrieve the heap and stack information from memory with corruption attacks. In this hypothetical scenarios I can see the password stored in the memory system because I can read your byte array or string. So if I change the data type to store the password, this doesn't add any level of security because the password is a plaintext as a string or as byte array. I think the true effort could be to add the protection with the cryptographic system. For example, the getPassword() could be retrive the hash of the Password and setPassword should be store the password as the hashed string. After that, we can override the sensitivities information contained in the string (or byte array), for me, it is the same (my opinion). I think the right way isn't changing the data structure to protect the information, but it is the cryptographic approach. Now, if I decrypt data and this info is stored in a security context (I store the plaintext in an encrypted heap), the clean password process can be useless and theoretically unnecessary to clean the sensitive data (this is a plus). |
Beta Was this translation helpful? Give feedback.
-
The point about not using String is that once a password is in a String as plaintext it remains, can't be zeroed etc. whereas a byte array (or char array) can. So returning a String for getPassword is really, well, wrong. Except that if it is needed as a String to get used then it's going to end up as a String anyway. As far as storing the the data as part of the database, well, as long as it's in memory then it's vulnerable if it is plaintext. So some level of obfuscation would be a good thing, probably. In addition to the links above, needless to say there is something on StackOverflow with lots of opinions on this. |
Beta Was this translation helpful? Give feedback.
-
Ok, I understand this point of view, and yeah, we can edit the getter/setter methods for the password as a char array. However, I think this link Guarded String can be util in this case adding a little level of protection |
Beta Was this translation helpful? Give feedback.
-
I've compiled all the relevant information in this post as I'm determined to address this vulnerability. It's a substantial challenge, but I'm committed to finding a solution. Considerations
Integration of Secure String ProjectI've experimented with the Secure String project and had success using the following code: public class Test {
static String readWholeBufferAsString(SecureCharBuffer buffer) {
char[] chars = new char[buffer.length()];
for (int i = 0; i < chars.length; i++) {
chars[i] = buffer.get(i);
}
return new String(chars);
}
public static void main(String[] args) {
SecureCharBuffer secureString = new SecureCharBuffer();
secureString.append("Hello");
final String test = readWholeBufferAsString(secureString);
System.out.println(String.format("Before closing secure buffer: %s", test)); // Prints Hello
secureString.close();
System.out.println(String.format("After closing secure buffer: %s", test)); // Throws an exception
}
} Proposed Solution
By adopting this approach, we significantly reduce the window of time during which sensitive data is present in plaintext in memory. While other projects rely on protected memory, our specific context might not allow for such implementation due to the uncertainty surrounding the possibility of encrypting portions of the Heap space. Your feedback on this approach is highly valued! |
Beta Was this translation helpful? Give feedback.
-
Noting that I turned #28 into this discussion. |
Beta Was this translation helpful? Give feedback.
-
Noting PR #52 from @giusvale-dev which I turned down as follows: Hi again Giuseppe Thanks for this PR which came as a bit of a surprise, especially since it comes so soon after your last contribution! There are two different aspects to this. On the one hand, offering passwords as strings through the API is wrong, and I am going to hold off on merging your PR for now, till we have thought about this a bit more, and in particular, thought about: How will we store the passwords in the database, not as strings, but as what? A couple of other things: Bumping the release to 2.2.3 isn't necessary as we didn't release 2.2.2 yet. If you think that whatever changes get made warrant going to 2.3 that would be a different question, I think. Jo |
Beta Was this translation helpful? Give feedback.
-
Maybe I have a solution that can help us in the following lines the possible fix:
Please give me your feedback, I'd like to develop these features. |
Beta Was this translation helpful? Give feedback.
-
closing - please continue the discussion under #60 |
Beta Was this translation helpful? Give feedback.
-
Entry.getPassword() returns a String. Since Strings are pooled and never GC'ed, there are effectively accessible throughout the JVM and can be read from a heap dump. It's a common practise to have passwords in byte arrays, instead. These arrays can be wiped by filling them with zeros.
Cf. Secure Coding standard recommendation:
https://wiki.sei.cmu.edu/confluence/display/java/MSC59-J.+Limit+the+lifetime+of+sensitive+data
Beta Was this translation helpful? Give feedback.
All reactions