8

I believe I'm misunderstanding a fundamental part of SecureString. I understand that string's are immutable and there a password or sensitive data is found as clear text on the heap.

What I'm struggling to understand is, how do I use SecureString in a client application which needs to verify the hashed password in a database?

Here's my context:

  • I'm using a WPF client application.
  • I have a local SQL database (on the client's machine)
  • The passwords are hashed and stored in the database.
  • The user tries logging into to my WPF application
  • The PasswordBox control stores the password in a SecureString via the SecurePassword property.

Now what? How do I hash a SecureString WITHOUT casting it back into string first?

All the advise I've received so far is to write extension methods converting SecureString to String, hash it and then send it to db to verify. But this defeats the whole exercise!

Must I just accept that SecureString is useless in my mentioned context and use plain string?

Niels Filter
  • 4,430
  • 3
  • 28
  • 42
  • 1
    Personally, I find very little use for SecureString - they add very little security to an application for all of the effort they take to actually use properly. At the end of the day, a truly dedicated attacker will get your password because it must be stored in memory **somewhere**... the idea that SecureStrings will make it harder is true, but if an attacker is already looking at memory then I assume they're dedicated enough to get past it anyways. – Alastair Campbell Jun 03 '15 at 11:20
  • 1
    Let the database deal with the password. Send the username and password to a stored procedure, which will return whether the authentication was successful. You can deal with all of the encryption stuff in the procedure. – Mike Eason Jun 03 '15 at 11:32
  • 4
    @MikeEason Send password as cleartext to a stored procedure? Never! – Sami Kuhmonen Jun 03 '15 at 11:35
  • I want to make a warning / addition to this as it is dependend to some details. for example you should a secure connection. otherwise "everyone" could read the password from the network stream. If he is usin secure strings its indicating that he wants to secure his passwords ;) @Niels have a look at my answer – Boas Enkler Jun 03 '15 at 11:35
  • @SamiKuhmonen Well, I'm no expert on this subject, it would be wise to encrypt the password before sending it, however it would then be required that the server, and the application would share the same encryption key(?). I would love to see a grand solution to that problem, if there is one! – Mike Eason Jun 03 '15 at 11:45
  • 2
    @MikeEason Passwords must not be *encrypted*, since that would suggest they can be decrypted. Rather they must be *hashed* with a one-way function. Then this is stored in the database and the user-submitted value is also hashed and these are compared. – Sami Kuhmonen Jun 03 '15 at 11:46
  • Sami is right, encryption in this scenario are always risky. Perhaps little better with asymmetric strategies (e.g. RSA) but thats somelike a whole different approach : ) – Boas Enkler Jun 03 '15 at 11:53
  • See also: http://stackoverflow.com/questions/18392538/securestring-to-byte-c-sharp – Gabe Jun 04 '15 at 12:28
  • @MikeEason There is no encryption key, just a shared hashing algorithm. More or less, the client takes whatever input the user typed in, perhaps with a salt, performs **some sort of algorithm on it**, (It doesn't really matter what type of algorithm, to be honest - it just needs to be repeatable, non-reversible and preferably with low chance of collisions) then checks to see if the database has the same hash, which is obviously saved into the database when the user account was created. – Alastair Campbell Jun 05 '15 at 11:49

1 Answers1

4

SecureString is represented as a byte[] you could encode the bytes e.g. with bitconverter and save the result. Furthermore SecureString is a encryption not a hash as it can be decrypted. (see below)

SecureString mainly meant to store sensitive data in memory. If you have a service / website, this is not as important as the values which are stored in the database. These should never be plaintext, and imo not be decryptable by your or any administrator Also i'm not sure wether another server could decrypt the strings, so you may have a problem when you change the server or have somekind of cluster scenario.

Especially for passwords would prefer using hash algorithms (e.g. SHA256) . These can't be uncrypted (like the sum of the digits). In the use case of a login funtionality you would encrypt the userinput and compare the hashs the user and and the one thats in the database. (details se below) I would also suggest to add a dynamic criteria like the userid to the hashinput so that 2 user with same password would have different hashes.

With this strategy you don't have a risc with userpasswords and therefore if data gets leaked it wouldn't be a problem at this point.

Here an short overview of using hash algorithms

So ( if the securestring is given) first decrypt the SecureString

String SecureStringToString(SecureString value){
  IntPtr valuePtr = IntPtr.Zero;
  try{
    valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
    return Marshal.PtrToStringUni(valuePtr);
  }
  finally{
    Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
  }
}

Than hash it for example with SHA256. From this post

  using (SHA256 hash = SHA256Managed.Create()) {
    Encoding enc = Encoding.UTF8;

    //the user id is the salt. 
    //So 2 users with same password have different hashes. 
    //For example if someone knows his own hash he can't see who has same password
    string input = userInput+userId;
    Byte[] result = hash.ComputeHash(enc.GetBytes(input));

    foreach (Byte b in result)
      Sb.Append(b.ToString("x2")); //You could also use other encodingslike BASE64 
  }

Store this hashsum. Depending on your encoding it may looke like this:

ac5b208b4d35ec79fa7c14b7a31f9c80392cdab2bc58bc5b79bcfe64b044d899

in your database. If the user signs on then create the hash from his input and compare it with the hash in the database. if they are equal then the password is correct. Therefore you never need to have the plaintext user password anywhere stored.

If the client makes the hash then it should absolut should no where exist as a plaintext (except the textbox if it doesnt support the securestring)

PS: this is only one option. But the main thing is to never store plaintextpasswords anywhere. For best never know them and have no change to get them decrypted.

Another strategy would be to use asymmetric encryptions like RSA but this can become more complex. If you need help with that i would recommend a dedicated post on this.

Depending on your requirements and envionment most of the time hashsums should be an acceptable solution. (But thats not an legal advice as i'm not a lawyer)

Community
  • 1
  • 1
Boas Enkler
  • 12,264
  • 16
  • 69
  • 143
  • 1
    Also it is advisable to add some kind of salt into the hashing process (simply append some constant random bytes to the bytes of the password). This will make using rainbow tables and other attacks on hashes more difficult. But this is also worth another whole post and information can be found on the web on this. – Sami Kuhmonen Jun 03 '15 at 11:49
  • Right ! das mentioned above the user id : ) Also it prevents some attacks if a user may get to know his hash he may look up other users with same hash. without salt he could login with his password. – Boas Enkler Jun 03 '15 at 11:52
  • 1
    Ah, true, didn't notice it there inside the code. Sorry :) – Sami Kuhmonen Jun 03 '15 at 11:53
  • 1
    I made it more clear with an comment in the code :) – Boas Enkler Jun 03 '15 at 11:55
  • @Boas Enkler, Thanks for the detailed answer. I'm fine with the hashing process etc and agree with you. You however mention I should _decrypting the SecureString and then hash it_, but the decrypt example and link you posted, brings the SecureString back into a string defeating the entire purpose I'm trying to achieve. Then I may as well just have used string. Did I misunderstand? – Niels Filter Jun 03 '15 at 14:19
  • The secure String is only needed if You hold Objekts with the password in ram – Boas Enkler Jun 03 '15 at 14:21
  • If my post solved your question please consider marking it as the solution – Boas Enkler Jun 03 '15 at 22:17
  • @Boas, But I do hold my password in RAM? I think we have a misunderstanding. When I capture the password from the user, the value gets stored into RAM (hence my need for SecureString). If you can show me a way of creating a hash from the SecureString instance without first going back to String, then I will mark you answer as the solution. – Niels Filter Jun 04 '15 at 08:40
  • As described above. First decrypt the secure string ( first example SecureStringToString) then you can hash the password and store it in the database – Boas Enkler Jun 04 '15 at 08:53
  • I appreciate the help, please re-read my question. "Is there a way for me to Hash the `SecureString`, **WITHOUT first casting it to `string`!**". – Niels Filter Jun 04 '15 at 12:16
  • 1
    You need to go directly from a `SecureString` to a `byte[]` without the intermediate `string` step first! – Gabe Jun 04 '15 at 12:18