fix(a7-auth): persist dummy key in owner-only sidecar
The store-wide dummy key was regenerated on every credentials_load, so an unknown user's dummy salt changed across daemon restarts while a real user's stored salt stayed stable -- a restart-gated username-enumeration oracle. Persist the 32-byte key in a 0600 <store>.dummykey sidecar next to the credential store. An absent sidecar is created with O_EXCL and fsynced; a present sidecar is read only when it is an owner-only regular file of exactly 32 bytes (otherwise the load fails closed). If the sidecar cannot be created (read-only mount, missing directory) fall back to a transient per-run key with a warning. A NULL store path keeps the key ephemeral.
This commit is contained in:
@@ -26,6 +26,15 @@
|
||||
* hard-rejected with an actionable "legacy" error; there is no auto-upgrade.
|
||||
* Use `fastsync-server --hash-credentials` to generate new-format lines.
|
||||
*
|
||||
* Alongside the store, credentials_load maintains an owner-only (0600)
|
||||
* `<store_path>.dummykey` sidecar holding the store-wide random dummy key. It
|
||||
* is auto-created on first load and MUST be preserved across restarts: it makes
|
||||
* the dummy challenge for an unknown user stable for the life of the store, so
|
||||
* a daemon restart cannot be used as a username-enumeration oracle. A sidecar
|
||||
* that is not an owner-only regular file of exactly 32 bytes fails the load
|
||||
* (fail closed); if it cannot be created (e.g. a read-only mount) the daemon
|
||||
* warns and uses a transient per-run key instead.
|
||||
*
|
||||
* Client --password-file format: the FIRST meaningful (non-comment, non-blank)
|
||||
* line is `user:password`, holding the literal password. The client keeps it
|
||||
* only for the duration of the handshake and wipes it at teardown; the file
|
||||
|
||||
Reference in New Issue
Block a user