Are passwords stored in memory safe?

  • I just realized that, in any language, when you save a password in a variable, it is stored as plain text in the memory.

    I think the OS does its job and forbids processes from accessing each other's allocated memory. But I also think this is somehow bypassable. So I wonder if it is really safe and if there is a safer way to store passwords to ensure that foreign processes can't access them.

    I didn't specify the OS or the language because my question is quite general. This is rather a computer literacy question than a specific purpose one.

    This is actually the weakness of encryption. Any non encrypted value or waiting to be encrypted is stored in memory in plain text.

    You might find some useful background in this question on Programmers.

    I remember article on Slashdot about a forensics technique exploiting DRAM fade latency: move RAM chips from a running machine to a different one quickly enough (the number was well within human ability) and you can easily dump the whole content.

    While other answers cover the "Safe as..." nuances well, if you are concerned, your platform/libraries may have a SecureString, or similar designed to minimize the risk. Such a construct might overwrite it's own memory as soon as you indicate you are done with it, as well as manage nuances of copies of itself introduced by garbage collection, etc.

    A good safety precaution is to overwrite the variable containing the password as soon as possible (easier in C/C++ than Java) and instead work with a derived key (e.g. generated using PBKDF2).

    @OmarKohl That's what I did for my script. I first ask the password to unlock the keyring. Then I encrypt a random session password I send to the remote computer. And once I'm sure it received the new password I overwrite the password of the keyring. If it doesn't really solve the problem, it limits the time when the actual persistent password is stored in memory.

    Related (as pointed out by someone on Hackernews):

    Doesn't HeartBleed give sections of memory to the attacker?

    @jkd Yes, but only memory from the processes that linked against the vulnerable version of OpenSSL. Unfortunately, this often would include passwords, but only for that specific process.

  • You are touching a sore point...

    Historically, computers were mainframes where a lot of distinct users launched sessions and process on the same physical machine. Unix-like systems (e.g. Linux), but also VMS and its relatives (and this family includes all Windows of the NT line, hence 2000, XP, Vista, 7, 8...), have been structured in order to support the mainframe model.

    Thus, the hardware provides privilege levels. A central piece of the operating system is the kernel which runs at the highest privilege level (yes, I know there are subtleties with regards to virtualization) and manages the privilege levels. Applications run at a lower level and are forcibly prevented by the kernel from reading or writing each other's memory. Applications obtain RAM by pages (typically 4 or 8 kB) from the kernel. An application which tries to access a page belonging to another application is blocked by the kernel, and severely punished ("segmentation fault", "general protection fault"...).

    When an application no longer needs a page (in particular when the application exits), the kernel takes control of the page and may give it to another process. Modern operating systems "blank" pages before giving them back, where "blanking" means "filling with zeros". This prevents leaking data from one process to another. Note that Windows 95/98/Millenium did not blank pages, and leaks could occur... but these operating system were meant for a single user per machine.

    Of course, there are ways to escape the wrath of the kernel: a few doorways are available to applications which have "enough privilege" (not the same kind of privileges than above). On a Linux system, this is ptrace(). The kernel allows one process to read and write the memory of the other, through ptrace(), provided that both processes run under the same user ID, or that the process which does the ptrace() is a "root" process. Similar functionality exists in Windows.

    The bottom-line is that passwords in RAM are no safer than what the operating system allows. By definition, by storing some confidential data in the memory of a process, you are trusting the operating system for not giving it away to third parties. The OS is your friend, because if the OS is an enemy then you have utterly lost.

    Now comes the fun part. Since the OS enforces a separation of process, many people have tried to find ways to pierce these defenses. And they found a few interesting things...

    • The "RAM" which the applications see is not necessarily true "memory". The kernel is a master of illusions, and gives pages that do not necessarily exist. The illusion is maintained by swapping RAM contents with a dedicated space on the disk, where free space is present in larger quantities; this is called virtual memory. Applications need not be aware of it, because the kernel will bring back the pages when needed (but, of course, disk is much slower than RAM). An unfortunate consequence is that some data, purportedly held in RAM, makes it to a physical medium where it will stay until overwritten. In particular, it will stay there if the power is cut. This allows for attacks where the bad guy grabs the machine and runs away with it, to inspect the data later on. Or leakage can occur when a machine is decommissioned and sold on eBay, and the sysadmin forgot to wipe out the disk contents.

      Linux provides a system called mlock() which prevents the kernel from sending some specific pages to the swap space. Since locking pages in RAM can deplete available RAM resources for other process, you need some privileges (root again) to use this function.

      An aggravating circumstance is that it is not necessarily easy to keep track of where your password is really in RAM. As a programmer, you access RAM through the abstraction provided by the programming language. In particular, programming languages which use Garbage Collection may transparently copy objects in RAM (because it really helps for many GC algorithms). Most programming languages are thus impacted (e.g. Java, C#/.NET, Javascript, PHP,... the list is almost endless).

    • Hibernation brings back the same issues, with a vengeance. By nature, hibernation must write the whole RAM to the disk -- this may include pages which were mlocked, and even the contents of the CPU registers. To avoid leaks through hibernation, you have to resort to drastic measures like encrypting the whole disk -- this naturally implies typing the unlock password whenever you awake the machine.

    • The mainframe model assumes that it can run several process which are hostile to each other, and yet maintain perfect peace and isolation. Modern hardware makes that very difficult. When two process run on the same CPU, they share some resources, including cache memory; memory accesses are much faster in the cache than elsewhere, but cache size is very limited. This has been exploited to recover cryptographic keys used by one process, from another. Variants have been developed which use other cache-like resources, e.g. branch prediction in a CPU. While research on that subject concentrates on cryptographic keys, which are high-value secrets, it could really apply to just any data.

      On a similar note, video cards can do Direct Memory Access. Whether DMA cannot be abused to read or write memory from other process depends on how well undocumented hardware, closed-source drivers and kernels collaborate to enforce the appropriate access controls. I would not bet my last shirt on it...

    Conclusion: yes, when you store a password in RAM, you are trusting the OS for keeping that confidential. Yes, the task is hard, even nigh impossible on modern systems. If some data is highly confidential, you really should not use the mainframe model, and not allow potentially hostile entities to run their code on your machine.

    (Which, by the way, means that hosted virtual machines and cloud computing cannot be ultimately safe. If you are serious about security, use dedicated hardware.)

    "virtual machines and cloud computing cannot be ultimately safe". I've always been skeptical about cloud computing.

    There is one more point to make. Somewhere, at some time, for some length of time, the plaintext simply *must* reside in "RAM". The entire exercise becomes rather pointless if the plaintext is never exposed to anyone anywhere. The upshot is that RAM, which is ostensibly never persisted and can be flagged as "protected", is about as safe as you'll get within the bounds of a computer system. Your point holds, however, that memory (and OS protections of same) are only regarded as safe because the alternative is not to use computers at all.

    To minimise the exposure of the sensitive data as clear text, various languages provide wrappers that make it easier to use Operating System facilities to prevent paging out. See e.g. .Net SecureString. However, this only mitigates the problem, doesn't solve it.

    A note about hibernation - if the file itself is encrypted (swap on dm-crypt for example) then password stored there is encrypted as well - and DMA - Firewire often allow DMA from devices to access the RAM (IOMMU would protect against it).

    I'm pretty sure I already knew all of this, but your powers of recall and ability to explain never fail to impress, thanks again Thomas.

    Moreover, if you loose your computer, and it's still powered on, it is relatively easy to recover contents of RAM by freezing memory chips and reading the content:

    kinda related, OpenGL is not required to clear the content of the framebuffer when creating buffers, so it is possible for a malicious program to grab what another program was drawing including those in non-visible buffers:

    A good summary. Only additional point I'd mention is that while the OS attempts to provide adequate protection and services to support secure operations, others actively attempt to find holes. Add to this varying levels of understanding, care and ability amongst programmers and we can conclude, there are no guarantees. As usual, we need to evaluate based on the risk, likelihood and subsequent impact and then decide best/necessary actions. This article does a good job in providing the basics to assist in understanding the risk. The likelihood and impact will depend on the individual situation.

    This is an interesting answer. What I would add is that most security is a delusion - if some one targets you specifically then you are usually screwed and often without cracking encryptions or being especially clever - but good old fashioned dirty tricks like stealing someones password by watching them enter it.

    I'd like to point out that, on Linux at least, `mlock` doesn't require root priv. There is, however, a strict limitation on how much memory you can lock if you're not root.

    What other model than the mainframe one is there?

    Re: "The OS is your friend, because if the OS is an enemy then you have utterly lost," a nice account of *how* the OS can be turned against you and *what* it can do if that happens, see Matthew Garrett's LibrePlanet 2013 talk from about 7m15s.

    You've covered almost all the angles, but you did not mention that registers get saved on the stack all the time and when a context or thread switch happens all the registers get dumped to memory yet again. Ergo keeping secrets in registers is not save either.

    @Johan That's correct, but the saved registers will not be swapped.

License under CC-BY-SA with attribution

Content dated before 7/24/2021 11:53 AM