This is a part of my series where I write about how I am overthinking the design of my password manager.
The primary way I interact with my current password manager, pass, is thorough passmenu. When users are faced with a password entry field, they trigger passmenu through a keyboard shortcut and enter the name of the password when prompted. This may then prompt me for their master password if it has been a while since they have last used the password manager. Once they enter their master password properly, passmenu types out the selected password into the currently focused field.
This flow works fairly well in the happy path, that is, when the master password does not need to be entered, and thus the site password is typed in immediately. However, it breaks down (sometimes dangerously) in some cases:
Failed master password attempts. pinentry, the underlying password entry program used by GPG (and thus pass), gives up after a few failed attempts. If a user fails all attempts, they must now try to figure out whether they succeeded or if they need to re-trigger passmenu with minimal feedback.
Success. If they see their password being entered immediately, then they have succeeded.
Failure. If they do not see their password being entered, they may have either failed or it may be pass being slow. Then, they must delay further to make sure that pass will not enter their passwords.
Navigating away or moving focus may be dangerous, as passmenu may later type out their password when they did not expect it to, possibly leading to a catastrophic secret leak.
This problem is compounded in cases when the focused window does not properly provide feedback for user input, such as
sudo. In such cases, the only reliable way to make sure the user’s password has been entered successfully is
Clear the current input (Ctrl+U or Backspace), since the user may have input their password correctly and passmenu may have typed out their password.
Trigger passmenu again.
If they are not prompted for their master password, it means their previous attempt had succeeded. They can now safely press enter and continue.
If they are prompted for their master password, it means their previous attempt failed. They have another attempt at their master password.
Master password prompt closes between attempts. pinentry also closes its window between attempts, with a noticeable delay before the window is reopened if the password is wrong. This forces the user to wait, trying to guess whether they typed in their password correctly with no feedback. Again, this allows the user to move the focus, possibly leading to the password being entered into the wrong field.
User expectation mismatch on caches. The master password prompt is only required if it is not cached from the last time it was entered by the user, usually controlled by the length of time since password entry (or usage). When user expectation of the master password cache does not match the password manager’s actual cache, the following things may occur:
Unexpected master password prompt. If the user was not expecting a master password prompt, they may be taking some sort of action when the master password prompt shows up. This is incredibly jarring, and may sometimes lead to a badly timed Enter key, which may either close the master password prompt or consume an attempt at entering their master password.
Unexpected lack of master password prompt. If the user is expecting a master password prompt (since it has been a while since they last used the password manager, for instance), they may start entering their master password. This may lead to their master password being leaked.
Now that we have learned the downsides of pass’s user interface design, we can try to how to mitigate them while preserving the generally straightforward workflow from pass + passmenu.
For this purpose, we make a few adjustments to the pass + passmenu user interface:
Master password unlock before password selection. The password manager should require a master password unlock before the user has to select the password name.
This adjustment provides several benefits:
All input entered by the user after triggering the password manager will be captured by the password manager. This prevents a potential secret leakage even if the user expected a master password prompt.
This design allows the password manager to protect the list of secrets as well as the secrets themselves, since the master password is available during password selection.
Once the user selects a password, they can be certain that their password will be entered shortly, allowing them to wait for the password manager to do its job without having to guess whether they need to retry.
One way this may fail is if the user starts entering their master password even when it is not required, and end up accidentally choosing a different site during password selection. This may lead to leaking passwords to different sites. In order to prevent this issue, the user must wait until getting visual confirmation of the password selection prompt, which must be fast enough to prevent issues with the user starting to type too quickly.
Master password prompt stays open in between attempts. Instead of closing immediately when the user presses enter, the master password prompt should instead indicate that the password attempt is being processed, eg. via a spinner. It should only close if the user cancels their action or the password is successfully accepted.
This also means that there are no password attempt limits, and the user is free to try as many times as possible. This is not a security issue, as an attacker trying to guess the password could easily mount an offline attack that does not use the password entry program instead.
This mode of operation also works better in the case of very slow key derivation. For security reasons, the password hash that is computed to check its validity may be extremely slow, to the order of seconds. Having the program close and give no feedback for that entire duration is poor user experience.