Are passwords stored in memory safe?
The shortcut
Conclusion: yes, when you store a password in RAM, you trust 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. [1]
What threats are we trying to defeat?
- adversaries with physical access to the device, including cold boot attacks (thieves, robbers, customs, or the local law enforcement have access to the userās device).
- unprivileged adversarial processes on the same host (malware, applies especially for Desktop)
- Bugs in the JS/Nim engine or runtime environment
- a partial compromise of the host OS kernel
As a side note, Bitwarden was recently tested and criticized by a Cāt magazine for not cleaning up their memory properly [2]
Node.js is currently meditating a solution: [3]
Beyond a partial compromise: Status Messenger Security Guarantees
Weāll describe the status appās security guarantees that we should thrive to achieve.
We define three states of the app: not running, unlocked (and running), and locked (and running; this state assumes the app was previously opened). We define the three states below:
Not Running
We refer to ānot runningā where the app has been installed, configured, and interacted with by the user, but has not been launched since the last reboot.
In the ānot runningā state the app guarantees:
There should be no data stored on disk that would offer an attacker leverage toward compromising the database stored on drive (e.g., the seed phrase, passphrase, keycard PIN, or derived cryptographic keys) stored in a configuration or log file).
The encryption should be designed in such a way that, so long as the user used a reasonable secure password, the attacker cannot brute force the passphrase in a reasonable amount of time using commonly available computing resources.
Running: Unlocked State
We define running in an āunlocked stateā as cases where the app is running, and where the user has typed in the seed phrase, the passphrase and/or the signing phrase to decrypt and access the messenger or wallet. The user may have displayed, copied to the clipboard, or otherwise accessed some of the appās secret contents.
In this ārunning, unlocked stateā the app guarantee:
It should not be possible to extract any secrets from memory, either directly or in any form that allows the original secret to be recovered without extraordinary computational effort.
For user data that has not been displayed/copied/accessed by the user since the app was unlocked, it should not be possible to access that data from memory.
Given usability constraints that affect the app, we acknowledge that:
It may be possible to extract user data from memory displayed/copied/accessed in the current unlocked session.
It may be possible to extract cryptographic data derived from the passphrase sufficient to decrypt other stored data, but not the seed phrase, passphrase, or keycard PIN itself.
Running: Locked State
We define āin locked stateā as cases where (1) the app was launched, but the user has not entered the passphrase yet, or (2) the user previously entered the passphrase and used the app, but subsequently clicked the āLockā or a ālock-timeoutā locked the app.
In this ārunning, locked state,ā the app should guarantee:
All the security guarantees of a not-running app should apply to an app that is in the locked state.
Since a locked app still exists as a process in virtual memory, this requires additional guarantees:
It should not be possible to extract the seed phrase, passphrase, or keycard PIN from memory, either directly or in any form that allows the original secrets to be recovered.
It should not be possible to extract from memory any cryptographic information derived from the passphrase that might allow sensitive user data to be decrypted without knowing the passphrase.
It should not be possible to extract any unencrypted messages or user data from memory that is stored in the app.
In addition to these explicit security guarantees, the Status app should incorporate additional hardening measures where possible, and to have these hardening measures enabled by default. For example, the app should attempt to block software keystroke loggers from accessing any secrets as they are typed, attempt to limit the exposure of unencrypted user data left in the clipboard, and take reasonable steps to detect and block modification or patching of the app and its supporting libraries that might expose passwords.
Potential next steps and best practices towards these guarantees
-
Feature: Memory safe (Auto-)App lock with opt-out [4] [5] [6]
-
Gradually implement explicit Memory Management; a static analyzer/linting (similar to [7] [8] helper that checks if a commit diff touched the secret set (Seedphrase, Private key, passphrase, Keycard pin). If so, suggest a) to apply the masked type to prevent log leaks b) apply explicit memory safety measures to the affected variables and references, for instance with libsodium.js memory_management [9] [10]
-
After the app has been locked, remove sensitive information by reloading the renderer process (similar to refreshing a web page) and apply memory safety measures to the secret set.
-
The inner state of external ciphers should be reset in memory as soon as possible. For instance, it should be verified that the algorithm that derives the private key from the seedphrase and the kdf that derives the .db key from the passphrase reset their internal state after use.
-
If the passphrase, seed phrase, or pin has to be kept in memory or handed over to third-party/libraries API, investigate if a KDF can be applied. For instance, SQL cipher allows to directly specify an encryption key instead of the library deriving one from the passphrase. If an external library is considered less trustworthy, we should derive a key from the passphrase in order to remain in control of the user provided secrets and their state in memory.
-
Limiting the traversal of secrets to OS provided APIs by implementing specialized/custom GUI elements, that are auditable, reusable and secure [11]
References:
[1] operating systems - Are passwords stored in memory safe? - Information Security Stack Exchange
[2] Erase Master Password in memory after login Ā· Issue #476 Ā· bitwarden/desktop Ā· GitHub
[3] Secure memory: Yay or nay Ā· Issue #30956 Ā· nodejs/node Ā· GitHub
[4] Encryption Key Storage Ā· Issue #6 Ā· bitwarden/clients Ā· GitHub
[5] Session Timeout Ā· Issue #29 Ā· bitwarden/clients Ā· GitHub
[6] [Auto-Logout] Implement Vault Timeout Options by vincentsalucci Ā· Pull Request #1194 Ā· bitwarden/clients Ā· GitHub
[7] https://eslint.org
[8] GitHub - jshint/jshint: JSHint is a tool that helps to detect errors and potential problems in your JavaScript code
[9] Secure memory - Libsodium documentation
[10] libsodium.js/dist/modules-sumo/libsodium-wrappers.js at 59fcebeed8fb23130964f5583fc9d0c8254f5274 Ā· jedisct1/libsodium.js Ā· GitHub
[11] Protected Confirmation | Android Open Source Project
[12] Secure MOR implementation - Windows drivers | Microsoft Learn