We know it's a good practice to prefer char[] over java.lang.String to store passwords. That's for the following two reasons (as I have read):
- char[] are mutable so we can clear the passwords after the usage.
- String literals goes to a pool that will not get garbage collected as other objects, hence might appear in memory dumps.
But java.sql.DriverManager doesn't have a getConnection() that comply with the above best practice because its password par开发者_开发百科ameter is String.
DriverManager.getConnection(String url, String user, String password)
I think the API should have an overloaded method with the following signature:
DriverManager.getConnection(String url, String user, char[] password)
What do you think about this? Do you see any alternative way to overcome this draw back?
Would love to hear your thoughts.
String literals go in a pool, but I wouldn't expect the password to be a literal (hardcoded in the program). I would expect it to come from a configuration or similar. As such it won't be a literal and will get garbage collected (provided all references are binned).
You make a good point, and most people answering are missing it. The worst case scenario is that the "temporary" password is swapped out by the OS, in clear text mind you. After this, this swap file is easily read, and on the disk can even survive being overwritten by zeroes if the attacker has about $1500 of equipment...
The best you can do is connect, password = null, followed by explicit call to gc(). If you are lucky, this will clear even strings used by driver implementations.
Any way...
- What you ask is currently not possible, but would be nice.
- Even char[] can survive certain conditions (e.g. swapping).
- Your password will get copied many times on the way to the database, so char[] solves only one part of the problem.
The reality is that unless the platform is designed specifically for security, all methods are only delaying tactics. Do, what you can, but if the determined person can gain access to your machine, char[] will gain you 1 hour max.
One can only speculate, unless you can ask the designer of the API.
My speculation is this:
The main API that uses char[]
instead of String
for passwords that I know of is JPasswordField
. It does so in order to allow the program to overwrite the user-entered password with other values once the values have been used (which is not possible with a String
, which will linger in memory at least until it is garbage-collected).
The password used to connect to a database is usually not user-entered in most applications I know, but comes from some kind of configuration/directory/...
Not matter where it comes from: the application is able to re-construct it once it is no longer known. This is the big difference between user-entered passwords and programmatically acquired passwords.
Since the password usually can be acquired on easier ways than to search through all the memory a program has used, fixing this attack vector is not a high priority
</speculation>
Your reason #2 is the one I've seen given most commonly for use of char[] over String. However, in general I think that if you assume that someone has access to your program state via a debugger or other means, there's no reason they can't also look at the contents of a char[].
The argument to use char[] arrays applies most where the user types the password, and you want to minimize the exposure of that password.
JDBC connections are almost never like that. The password is stored in some configuration file, perhaps obfuscated, and is a much bigger source of a leak than the potential to read memory.
Anyway, the JDBC standard allows for passing passwords in properties objects and even in the URL, so I think having a char[]
password parameter would give you a false sense of security.
If you have a real use case where the password needs to be removed from memory as quickly as possible to be unrecoverable, and that otherwise makes sense in the context of a real JDBC application, I would love to hear it. I can imagine that such a thing could exist, but I can't think of a scenario where the use of a char[]
really makes things more secure.
Your point 1 is valid to some extend, but point 2 about Strings ending up in a uncollected string pool is only true for static literal strings (strings that appear directly in the code). If you would have passwords stored directly in your code I'd recommend to worry about these first as it is far easier to find them in classfiles then in a running VM.
So if you think you must store your passwords in a char[] you can still create a String object from it before you call getConnection(). If the driver implementation doesn't store the string object internally it will quickly not be reachable anymore and thus get collected pretty fast. The only chance to still read it back then is to examine the memory of the JVM directly where it still might exist. So you are right that using a char[] would be a bit more secure but not much as the password would have to be in the memory at the some point anyway.
I.e. a very simple way to grab the password with any kind of API would be to inject a faked SQL driver and to grab the password directly in the connect method. Whoever is able to examine the JVM memory to find a not yet overwritten password string in it will also be able to do inject a modified driver jar.
精彩评论