问题
I have been writing a little program for myself using C# that I can use to store my passwords and then retrieve them for viewing/editing.
While the passwords are stored to disk in an encrypted format, when they are read into memory for display/editing on a form, they are unencrypted.
I have learned that having unencrypted passwords in memory is a pretty big security problem, so I came across the SecureString
class.
Would there be a more secure way to do this than using the SecureString
class, or does SecureString
live up to its name?
回答1:
SecureString
keeps its text encrypted in the memory and you can dispose it immediately when you don't need it. The problem is, when you want to display it or use it in almost any other way, you have to convert it to normal string, which is not secure.
Also, I wouldn't rely on it too much – the system is able to decrypt it without any decryption key, which means determined hacker will most likely be able to do the same. When a hacker gains control of your computer, you can't be sure of anything and he will be probably able to access anything that's not encrypted using a good algorithm with good key.
回答2:
SecureString goes some way to secure the in memory instance of a string, however you should be aware of some significant drawbacks.
- A SecureString (just as svick points out) can be retrieved without a decryption key, so any hacker skilled enough to retrieve this chunk of memory you can safely assume can easily perform this minor operation to retrieve the plain text string. Consider the simplicity of
SecureStringToBSTR(input);
SecureString needs to be populated in a character by character way as there is no .Text property Get or Set accessor to use. On blogs including MSDN you will often see code like the following:
public static SecureString StringToSecureString(string input) { SecureString output = new SecureString(); int l = input.Length; char[] s = input.ToCharArray(0, l); foreach (char c in s) { output.AppendChar(c); } return output; }
The significant issue with this code is that the developer allowed the input
string to ever exist in memory in the first place. The User Control or WinForm TextBox of PasswordBox used to collect this password from the user should never collect the whole password in one operation, as
- Hackers can access memory directly and retrieve the password directly from the control on the stack or inject code to retrieve the password on the instantiation of this method
- If your last Memory Dump still resides on your machine from your last blue-screen, and this control was populated with your plain text password, then the password is sitting in a tidy little file ready for your Hacker to pick up and use at his/her leisure.
Instead consider options where the KeyPress is used to retrieve each character from the user, otherwise, WPF's PasswordBox is backed by a SecureString by default I believe (someone else may confirm this).
Finally there are much more simple ways to collect passwords from users like Key Loggers. My recommendation is to consider your user demographic, exposure risk, and determine whether something as trivial as a SecureString is really going to cut it.
回答3:
SecureString is exactly what the name says and you guesed: It saves the string also encrypted in memory, so yes it is the correct way to go.
See HERE:
Represents text that should be kept confidential. The text is encrypted for privacy when being used, and deleted from computer memory when no longer needed. This class cannot be inherited.
回答4:
You guys are making this WAY too complicated. No one asked if this was the best way to solve the problem. They just want to see some working code. Jeez. In this example, passwordPre is a string that was decrypted from a resource (e.g. a config file) using your proprietary decryption algorithm.
string passwordPre = DecryptProprietary(objectReferringToPassword);
char[] passwordChars = passwordPre.ToCharArray();
System.Security.SecureString securePassword = new System.Security.SecureString(); // in production, this should probably be a global variable
foreach (char c in passwordChars)
securePassword.AppendChar(c);
string decryptedPassword = new System.Net.NetworkCredential(string.Empty, securePassword).Password; // this is how to convert it to a string for quick usage to access the protected resource
So you use the decrypted password quickly to gain access to whatever resource you need and you dispose of it by exiting the method.
来源:https://stackoverflow.com/questions/6483723/securestring-for-storing-in-memory-and-presenting-passwords-or-something-else