22

Let's say I've retrieved an encrypted secret key from the server. I decrypt it to get the actual secret key, assign the decrypted key to a variable in my app. Something along this:

const encryptedKey = fetchKeyFromServer();
const secretKey = decrypt(encryptedKey);
//Now, the variable secretKey has the actual secret key in memory

Now, is this a vulnerable thing to do in terms of security? Since I've stored the decrypted key in the memory, is there a chance that somebody might be able to reveal the secret key by reading off from the app's memory?

However, if I don't assign the decrypted key to a variable, how should I use the key? I've thought of assigning the encrypted key to the variable and decrypt it every time I need to use it. But I'm still not sure if this is the best way to do things.

Anders
  • 65,582
  • 24
  • 185
  • 221
xenon
  • 367
  • 3
  • 7
  • Do you have a specific programming language in mind? – Sjoerd May 10 '17 at 06:45
  • @Sjoerd I'm using javascript with react native. so the app will be deployed onto phones. – xenon May 10 '17 at 06:46
  • 5
  • @Sjoerd thanks! looks like from the accepted answer, there is no way I can clear sensitive memory in JS. :( – xenon May 10 '17 at 06:58
  • Who owns/controls the machine this program will run on? The secret key's owner or someone else? – das-g May 10 '17 at 12:22
  • @das-g It's going to be someone else, not the secret key's owner. :/ – xenon May 10 '17 at 12:30
  • Then you should look into a solution that doesn't require the application to know that secret key. (Maybe it really just needs the public key? Or maybe it can use the user's secret key? This really depends on what you use the key for.) – das-g May 10 '17 at 13:46
  • decrypt(encryptedKey) ?, what keeps an attacker from executing the same function ? – HopefullyHelpful May 10 '17 at 15:06
  • This is a case where obfuscation can be useful. Someone reverse engineering your code might find it pretty easy to find the binary code corresponding to the code in the OP. By obfuscating your code if makes this discovery more difficult. (If the attacker knows that a key is being retrieved and being decrypted, he has valuable information. Depending on the circumstances this may allow him to obtain "secretKey" from his own program.) Also decrypt() doesn't take a decryption key (the only argument is data to decrypt), so it can be reversed engineered and utilized without secret knowledge. – Χpẘ May 10 '17 at 18:39

1 Answers1

32

Yes, it does mean that the key will be stored in the application’s memory. Yes, there is a risk that malware (with sufficient privilege) can read it from there. This risk is hard to avoid — if you want to use the key, you need to put it in memory, just as you need to put your house key in your pocket after you lock the door.

This is usually not considered a big deal for one reason — if there is malware with root privileges on a computer it’s already game over anyway. There is no way to keep anything safe at that point. Even if you don’t decrypt the key, the malware could just read the key that is used for that decryption from wherever it is stored.

Here are three things you can do to mitigate the risk:

  • Use some kind of HSM. (Thanks to DRF for pointing this out.) This is the best approach, but the feasibility depends on what platform you are working on. Do note though, that malware with enough privilege to read other processes’ memory can probably use the HSM as well. So this is not bulletproof against a malware infection.
  • Minimize the time the key is in memory to shrink the attack window by overwriting the memory after you are done. (As MSalters points out, this might not be as straight forward as it sounds. E.g. in C++ the optimizer might remove a write that is not read, and in Java strings are imutable so they can not be overwritten.)
  • As Vitor suggests, mark the memory page the key is stored on as unswappable so that it is never written to disk.
Anders
  • 65,582
  • 24
  • 185
  • 221
  • 6
    You are ignoring possible other solutions such as HSM's which can solve this problem at least partially (you still end up with plaintext in memory but not keys). Since more and more devices have some form of partial HSM built in, in the form of a dedicated security chip or a smart card, this becomes more feasible. – DRF May 10 '17 at 08:07
  • @DRF Fair point. I have updated my answer. Thank you! – Anders May 10 '17 at 08:43
  • Kind of an example of the Analog Hole. – FMaz May 10 '17 at 10:03
  • 17
    "In a language like C++ it is fairly simple — you just write zeroes over the memory where you stored it.". And then the optimizer says "hey, that's a write without subsequent read, let's optimize that". That's why Windows has ZeroMemory and SecureZeroMemory – MSalters May 10 '17 at 13:02
  • @MSalters Did not know that. Have updated the answer. Thank you! – Anders May 10 '17 at 13:10
  • 2
    Another good thing is to tell the OS to mark the memory page where your key is stored as non-swappable, to avoid having it written on permanent storage – Vitor May 10 '17 at 14:28
  • 2
    If you are using .NET, you can use a SecureString. Unfortunately the documentation suggests this is not available for mobile, but could be useful for anyone writing a Windows desktop app. – IllusiveBrian May 10 '17 at 14:47
  • @IllusiveBrian Good point - I have added it. Thank you! (Feels like my rather quick first answer now is more the work of good and insightful commentators...) – Anders May 10 '17 at 15:14
  • 2
    From what i've seen, SecureString is very easy to use incorrectly. If you ever convert it to a string, or have an array containing the characters/bytes in the key, you've just tossed out nearly all the protection it can offer you. – cHao May 10 '17 at 15:17
  • @Anders It looks like you confused my comment with Vitor's – IllusiveBrian May 10 '17 at 15:18
  • 1
    Malware that can use the HSM can still decrypt things with the key (etc)., but can't copy the key to a different machine and use it there. That's a big difference in level of privilege, and how damaging/containable a successful attack is. – Charles Duffy May 10 '17 at 15:38
  • @IllusiveBrian Ooops... – Anders May 10 '17 at 16:21
  • @IllusiveBrian: For some reason, .NET doesn't provide any practical function to read out bytes from a secure string, but requires that the string as a whole be marshaled into unmanaged storage which creates its own problems. I understand that reading a SecureString as a string or even a Char[] would undermine security, but code that reads characters individually would never have to hold the entire key outside the SecureString in any form. – supercat May 10 '17 at 22:05
  • @MSalters A cast to a volatile type should take care of that too, I believe. – Angew is no longer proud of SO May 11 '17 at 12:05