When would I need a SecureString in .NET?

2019-01-02 16:44发布

I'm trying to grok the purpose of .NET's SecureString. From MSDN:

An instance of the System.String class is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created and it is not possible to predict when the instance will be deleted from computer memory. Consequently, if a String object contains sensitive information such as a password, credit card number, or personal data, there is a risk the information could be revealed after it is used because your application cannot delete the data from computer memory.

A SecureString object is similar to a String object in that it has a text value. However, the value of a SecureString object is automatically encrypted, can be modified until your application marks it as read-only, and can be deleted from computer memory by either your application or the .NET Framework garbage collector.

The value of an instance of SecureString is automatically encrypted when the instance is initialized or when the value is modified. Your application can render the instance immutable and prevent further modification by invoking the MakeReadOnly method.

Is the automatic encryption the big payoff?

And why can't I just say:

SecureString password = new SecureString("password");

instead of

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

What aspect of SecureString am I missing?

11条回答
妖精总统
2楼-- · 2019-01-02 17:26

There are very few scenarios where you can sensibly use SecureString in the current version of the Framework. It's really only useful for interacting with unmanaged APIs - you can marshal it using Marshal.SecureStringToGlobalAllocUnicode.

As soon as you convert it to/from a System.String, you've defeated its purpose.

The MSDN sample generates the SecureString a character at a time from console input and passes the secure string to an unmanaged API. It's rather convoluted and unrealistic.

You might expect future versions of .NET to have more support for SecureString that will make it more useful, e.g.:

  • SecureString Console.ReadLineSecure() or similar to read console input into a SecureString without all the convoluted code in the sample.

  • WinForms TextBox replacement that stores its TextBox.Text property as a secure string so that passwords can be entered securely.

  • Extensions to security-related APIs to allow passwords to be passed as SecureString.

Without the above, SecureString will be of limited value.

查看更多
栀子花@的思念
3楼-- · 2019-01-02 17:30

One of the big benefits of a SecureString is that it is supposed avoid the possibility of your data being stored to disk due to page caching. If you have a password in memory and then load a large program or data set, your password may get written to the swap file as your program is paged out of memory. With a SecureString, at least the data will not be sitting around indefinitely on your disk in clear text.

查看更多
无与为乐者.
4楼-- · 2019-01-02 17:32

I guess it's because the string is meant to be secure, i.e. a hacker should not be able to read it. If you initialize it with a string, the hacker could read the original string.

查看更多
宁负流年不负卿
5楼-- · 2019-01-02 17:34

I believe the reason why you have to do character appending instead of one flat instantiation is because in the background passing "password" to the constructor of SecureString puts that "password" string in memory defeating the purpose of secure string.

By appending you are only putting a character at a time into memory which is likley not to be adjacent to each other physically making it much harder to reconstruct the original string. I could be wrong here but that's how it was explained to me.

The purpose of the class is to prevent secure data from being exposed via a memory dump or similar tool.

查看更多
初与友歌
6楼-- · 2019-01-02 17:39

Some parts of the framework that currently use SecureString:

  • WPF's System.Windows.Controls.PasswordBox control keeps the password as a SecureString internally (exposed as a copy through PasswordBox::SecurePassword)
  • The System.Diagnostics.ProcessStartInfo::Password property is a SecureString
  • The constructor for X509Certificate2 takes a SecureString for the password

The main purpose is to reduce the attack surface, rather than eliminate it. SecureStrings are "pinned" in RAM so the Garbage Collector won't move it around or make copies of it. It also makes sure the plaintext won't get written to the Swap file or in core dumps. The encryption is more like obfuscation and won't stop a determined hacker, though, who would be able to find the symmetric key used to encrypt and decrypt it.

As others have said, the reason you have to create a SecureString character-by-character is because of the first obvious flaw of doing otherwise: you presumably have the secret value as a plain string already, so what's the point?

SecureStrings are the first step in solving a Chicken-and-Egg problem, so even though most current scenarios require converting them back into regular strings to make any use of them at all, their existence in the framework now means better support for them in the future - at least to a point where your program doesn't have to be the weak link.

查看更多
荒废的爱情
7楼-- · 2019-01-02 17:39

Well, as the description states, the value is stored encrypted, with means that a memory dump of your process won't reveal the string's value (without some fairly serious work).

The reason you can't just construct a SecureString from a constant string is because then you would have an unencrypted version of the string in memory. Limiting you to creating the string in pieces reduces the risk of having the whole string in memory at once.

查看更多
登录 后发表回答