2

i'm trying to achieve the following:

In order to make sure the client machine holds sensitive data (in SecureString) as least as possible:

  • Pin a byte array to memory holding a BSTR of the sensitive string (SecureString)
  • transfer the sensitive data byte by byte using WCF (clearing each byte every send)
  • after everything is received, the server needs to decode the bytes and right back into strings

i'm very concered about encoding - i understand that C# holds strings data as UTF-16, but is it possible that it will not be interpreted well when doing the following?:

  • client machine converts to BSTR -> into bytes -> sending over the wire (WCF)
  • server gets the BSTR array, and converts it back to string

should i worry about encoding? thanks!

=== EDIT - possible solution===

After consulting with EBrown, he found that microsoft uses the following BOM: https://msdn.microsoft.com/en-us/library/windows/desktop/dd374101%28v=vs.85%29.aspx

to convert into BSTR Bytes, i'm using the following method (it's a bit changed internally): https://stackoverflow.com/a/25190648/1845545

And, because C# uses UTF-16 encoding, i'll convert it back using: Encoding.Unicode.GetString(bt);

Community
  • 1
  • 1
ArielB
  • 1,184
  • 2
  • 11
  • 36
  • It should convert it properly, provided both systems have the same endianness. (I.e. big-endian, little-endian.) If they do not have the same endianness, I'm not sure if reading byte-by-byte would cause issues or not. – Der Kommissar May 13 '15 at 13:22
  • 1
    So in order to make a `SecureString` more 'secure' you are going to expose it on the network? How is the WCF communication secured? And why would you send the string char by char as opposed to one single string? What you're doing has all the alarm smell of 'in-house' security... – Remus Rusanu May 13 '15 at 13:28
  • 1
    @RemusRusanu 2 answers: if you hold a C# String in memory - it's only cleaned whenever the CLR feels like it (C# does string interning), so your password is exposed. that's why i need byte by byte. about the network - i'm using HTTPS. the only concern is that i want to hold the password in memory as short time as possible. exposing it only when sending it over the network, clearing it afterward. both machines should have the same endianess as they are windows. – ArielB May 13 '15 at 13:31
  • @EBrown - that's because C# holds strings as UTF-16 right? (that's the only reason) – ArielB May 13 '15 at 13:32
  • Yes, UTF-16 is not endian-neutral, there is something called a BOM that is supposed to be at the beginning of a UTF-16 string which is two bytes (FEFF) that are used to determine what endianness is used. Both systems being Windows is irrelevant. The hardware determines endianness. http://en.wikipedia.org/wiki/Byte_order_mark Basically, FEFF is Big-Endian, FFFE is Little-Endian. – Der Kommissar May 13 '15 at 13:34
  • 1
    As soon as the data goes into WCF you lose control. You can't clear the byte anymore. It's in internal WCF buffers now. You are fighting windmills. Realistically nobody is reading your process memory. If they can you have already lost. Invest the dev time elsewhere to make the app more secure with real security. – usr May 13 '15 at 13:40
  • 1
    @usr - we've already have a method that causes the entire data to not reside in memory during transmission - so we're clear. i haven't lost as long as i'm keeping the password as secured as possible. if what you're saying is correct, then SecureString never has any value. i'm asking only about encoding. that's all. – ArielB May 13 '15 at 13:48
  • @EBrown I Understand, so it means i should be fine. – ArielB May 13 '15 at 13:50
  • @ArielB No, because this BOM is not present in the in-memory representation of the string. You would have to include your own BOM to insure the correctness. – Der Kommissar May 13 '15 at 13:51
  • 1
    Indeed, SecureString pretty much never has any value. Under what concrete scenario do you think it will help you? Do you expect attackers to read your memory? – usr May 13 '15 at 13:52
  • @usr - yes, i definitely expect attackers to read my memory. as i said, i have a solution that keeps the bytes in memory for a very short time, then it disposes it. this has tremendous value for us and as always i know that client machine protection is hard, but atleast you can make the attacker's life much harder – ArielB May 13 '15 at 13:54
  • 1
    @EBrown do you know how WCF handles this? as if i send a regular string, i never have to worry about encoding. – ArielB May 13 '15 at 13:57
  • You may not have to worry about it, I'm not sure how `SecureString` works or how you are implementing it. If you are doing byte-by-byte writing of memory, then it's very important that you pay attention to the BOM. If you are doing character-by-character writing of a string, then you won't have to worry about it I suspect. – Der Kommissar May 13 '15 at 13:58
  • @EBrown i'm converting the secure string into BSTR - Marshal.SecureStringToBSTR(secureString); then i'm going over the pointer and placing it into a pinned array, releasing it when i'm done using it. – ArielB May 13 '15 at 14:04
  • Alright, I managed to finally find some concrete information (https://msdn.microsoft.com/en-us/library/windows/desktop/dd374101%28v=vs.85%29.aspx): `Microsoft uses UTF-16, little endian byte order.` – Der Kommissar May 13 '15 at 14:08
  • @EBrown So if i understand correctly, can i take the converted bytes and use Encoding.Unicode.GetString(bt)? i'm converting it using the following method of Eric's solution: http://stackoverflow.com/questions/18392538/securestring-to-byte-c-sharp (pinning is missing there though) – ArielB May 13 '15 at 14:27
  • Yeah, from what that document says (which is literally that only line I posted) Microsoft uses Little-Endian for strings, always. Which means a byte-by-byte copy can be byte-by-byte read properly on the other side. – Der Kommissar May 13 '15 at 14:28
  • @EBrown allright! Thanks, so i'll post your suggestion in the body of the question, and i'll use that including testings. If you want you can compose an answer and i'll mark it as an answer? – ArielB May 13 '15 at 14:31
  • 1
    @ArielB please be careful. A BSTR is essentially a Unicode string - the bytes are the same as those in a `String` class. You are dropping whatever protection you had by using a SecureString to send your data in cleartext. All the conversions back and forth do nothing more than what WCF's serializer would do by itself, without BOM and encoding ambiguities. You gained nothing, you broke security *and* you introduced encoding issues – Panagiotis Kanavos May 13 '15 at 14:42
  • @PanagiotisKanavos i understand, but this time, i can clear the byte array as soon as possible from memory, which i can't do with a managed C# String. I wish i could use SecureString over the network, but target machine will not be able to decrypt it. i know that WCF serialize does it, but i'm trying to never use a raw C# String, but only a pinned byte array that is destroyed once the request finishes – ArielB May 13 '15 at 14:49
  • Then encrypt the data (probably using asymmetric encryption) instead of storing it in a SecureString and send the encrypted data to the other side. There *are* standards that ensure the other side can decrypt it. That's infinitely better than sending sensitive data in cleartext – Panagiotis Kanavos May 13 '15 at 15:05
  • To put it another way - who cares about the memory when you can use Fiddler to read the password? – Panagiotis Kanavos May 13 '15 at 15:07
  • @PanagiotisKanavos we understand that mitigation aswell and we talked about it. asymmetric encryption will require a public key, which can be also replaced with a "fiddler" one. currently we're handling the memory issue task which is also a big threat – ArielB May 13 '15 at 15:17

1 Answers1

2

SecureString is already providing protection against core dump or swap file leaks and even some protection against reading the process memory:

the value of a SecureString object may use a protection mechanism, such as encryption, provided by the underlying operating system

The quotes 'operating system mechanism' is CryptProtectMemory:

The CryptProtectMemory function encrypts memory to prevent others from viewing sensitive information in your process. For example, use the CryptProtectMemory function to encrypt memory that contains a password. Encrypting the password prevents others from viewing it when the process is paged out to the swap file.

By attempting the scheme you're propping all you'll achieve is just a severe weakening of the security provided by the SecureString. You expose the the password in the process memory during the transit in WCF, you are exposing your your password by unnecessarily using the network (HTTPS won't protect against things like the Lenovo SuperFish MITM, and there are more).

Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
  • 1
    i understand, but i can't send a SecureString over the network as it will be irrelevant in the server. that's why i'm trying to make it in the memory as short as possible. what other solution do i have to transmit the password over the network? – ArielB May 13 '15 at 14:02
  • 1
    Why *are* you sending a password over the network? Why aren't you using the authentication mechanisms provided by WCF? – Panagiotis Kanavos May 13 '15 at 15:09
  • 2
    @PanagiotisKanavos can you elaborate what's the difference? we're using a logon service that returns AuthToken that is used in other calls later. why is WCF logon method more secured than a regular one? as user and password need to be sent anyway from the client. – ArielB May 14 '15 at 08:46