Safe use of SecureString for login form

12,929

Solution 1

If you believe that you need SecureString you must believe that an attacker can read your process memory, too. If the latter is true he can read the password characters as they are typed, or read from the textbox internal character buffer directly, or read pixels off the screen.

This is an unrealistic scenario. Don't use SecureString. It helps little and steals your time.

Cold boot attacks are more real, yet extremely uncommon. They require physical machine access which usually totally owns the machine. Reading by the attacker is the least of your concerns in this case.

Basically, you have to contrive a case where your developer time is well spent using SecureString.

Solution 2

First of all, I'd like to state that I agree with usr - don't bother.

Now to the details:

  • This answer provides great background for the discussion.
  • This is a TextBox control that utilises SecureString. I have not used this so I can't comment on the quality, but being on MS blog I don't expect it to be anything but proper.
  • To answer the question about passing the data to System.Security.Crypto, basically you can't and no amount of unmanaged memory marshalling will help you, since during the process of such marshalling the string gets decrypted. It has to because otherwise it can't be consumed by your target API. If you are using CSP or X509Certificate, you can use SecureSctring because these are supported in the framework, but that's about it.
Share:
12,929

Related videos on Youtube

KeithS
Author by

KeithS

Updated on June 29, 2022

Comments

  • KeithS
    KeithS almost 2 years

    So there's this class that seems very seldom used: SecureString. It's been around since 2.0 at least, and there are a few SO questions on it, but I thought I'd ask my own specific questions:

    I have a LoginForm; simple WinForms dialog with username and (masked) password fields. When the user enters both and clicks "Login", the information is passed to an injected authentication class that does a layer of key-stretching, then hashes half of the stretched key for verification while the other half is the symmetric key for the encrypted user account data. When all this is through, the loginForm is closed, the authenticator class disposed, and the system moves on to loading the main form. Pretty standard stuff, maybe a little more involved than the standard hash-the-password-and-compare, but the simple hashed password would be defeated in my case by storing the user data in plaintext, because that data includes credentials for a third-party system (and we all know how people like to reuse passwords).

    Here's the first question; how would I use SecureString to retrieve the password from the Password textbox, without it being exposed as an ordinary System.String through the Text property of the textbox? I assume there's a way to access the unmanaged GDI window for the Textbox that's being wrapped by the CLR classes, and pull the text data in using the Marshal class. I just don't know how, and I can't seem to find good information.

    Here's the second question; once I have the password as a SecureString, how do I pass it to a hash provider from the System.Security.Crypto namespace? My guess is that I'd use Marshal.SecureStringToBSTR(), then Marshal.Copy() from the returned IntPtr back into a byte array. I can then call Marshal.ZeroBSTR() to clean up the unmanaged memory and I can zero out the managed array with Array.Clear() once I have the hash. If there's a cleaner way that allows me full control over the lifetime of any managed copy of the memory, do tell.

    Third question; Is all this really necessary, or is the inherent insecurity of System.String in a managed-memory environment a little overblown? Anything used to store the password, encrypted or otherwise, should be out of scope and on its way to the garbage collector long before the OS would consider swapping the app into virtual memory (allowing the password to be sniffed from the swap-file after a hard shutdown of the computer). A cold-boot attack is a theoretical possibility, but really, how common is this? The bigger concern is the now-decrypted user data, which hangs around as part of the user for the entire application lifetime (and thus would be a prime candidate for using SecureStrings, as except for a couple of basic usages they stay pretty dormant).

  • Andrew Savinykh
    Andrew Savinykh over 11 years
    The idea is to reduce attack surface. For example, if attacker can't read memory but can access swap file, SecureString can help. We can never predict what attacker can or can't do, so we are trying to makes things most difficult for them. But yeah, no amount of protection helps: if the app knows the information - an attacker potentially can too.
  • usr
    usr over 11 years
    I guess the best argument against SecureString is that developer time is best spent elsewhere.
  • KeithS
    KeithS over 11 years
    Well, I don't have to believe that an attacker can see characters being typed in, to believe that the attacker could pull a swap file. The levels of sophistication and required access are very different. So, I can foresee an advantage to SecureString in a not-too-contrived scenario of needing sensitive data kept in memory long-term (like the aforementioned third-party system credentials which live as long as the app does and could well end up in the swap file). But I think I agree with your viewpoint that 9 times out of 10 it's more trouble than it's worth.
  • Montre
    Montre over 11 years
    @KeithS Arguably in the case you describe that third party system uses an authentication scheme that's too naive, and ideally should be redone to use more secure auth tokens of some sort for persistent logins.
  • KeithS
    KeithS over 11 years
    True; in my case the third-party credentials are needed at app startup, post-login, to log the user into the third-party system, and then they can be cleared out as well. The only other time they're really needed is when they're changed, and that never happens to the instance of the user record that's been authenticated.
  • KeithS
    KeithS over 11 years
    I don't think the problem is in decrypting the string (admittedly my knowledge on this is light). I think the problem is in producing a System.String, over which the developer has no control in terms of lifetime; it's created on the heap and sticks around as long as the GC doesn't collect it (which may or may not happen before being swapped to VM). A byte array, OTOH, can be zeroed out in-place, and the unmanaged IntPtr can be properly cleaned up and freed as well, all of that hopefully within the CPU cache or RAM, and not the swap file, because it's being actively used.
  • Andrew Savinykh
    Andrew Savinykh over 11 years
    Well, you should not be really counting on that zero-ing a byte array in place. Garbage collector shuffles memory around all the time, there could be multiply copies of your byte array. If you target API is managed then you have very little control of the type you are after.
  • KeithS
    KeithS over 11 years
    If the GC's moving memory around (as I know it does) I would hope it has the sense to clean up after itself during or after heap optimization. I trust the GC to work with memory in an efficient way, because I can do no other if I want to work in a managed runtime at all (and I do, because it's so much easier than VC++). But, I know that the GC is not at my beck and call, that being the primary problem when writing secure code in managed runtimes.
  • Andrew Savinykh
    Andrew Savinykh over 11 years
    I do not know for sure if it cleans up or not. I would assume that it does not, but you might be right.
  • M.Stramm
    M.Stramm about 9 years
    @usr Using SecureString is a step into the right direction, using it right is hard and if it's used wrong, it may introduce a wrong sense of security, however recommending not to use it altogether is definitely misleading. You might as well recommend not using a password system, since it will be broken anyway and so is not worth the time.
  • usr
    usr about 9 years
    @M.Stramm My point is that the tradeoff between time invested and security gained is very tilted. Your analogy to password systems does not apply.; Would you recommend a customer to pay you to use SecureString and invest the time? I think not. It's not worth the money except in contrived cases. Would you recommend a password system? Clearly yes. This is the difference.
  • M.Stramm
    M.Stramm about 9 years
    @usr You do not sell SecureString to a user, you sell a "security feature". There are .Net APIs which consume SecureString and WPF's PasswordBox uses it internally (and exposes it via property) which relieves the pain points at least in the cases where you can use WPF for your UI and said .Net APIs. Thus I still maintain that recommending against it generally is bad advice
  • usr
    usr about 9 years
    To clarify: By "customer" I meant the person who gives you money to develop software.