基于ntfy的Vaultwarden远程解锁方案设计评审:防止受入侵主机暴露.env密码
Stack Overflow Style Answer
Great question—your home lab setup already has strong security guardrails, and fixing the key leakage gap just needs a targeted tweak to your secret handling workflow. Let’s walk through a practical, cryptographically sound solution that checks all your boxes:
Core Strategy: Shamir's Secret Sharing + Ephemeral Session Encryption
The main flaw in your current design is that P2 travels in a form an attacker can intercept and reuse. We’ll fix this by:
- Using Shamir's Secret Sharing (SSS) to split your GPG password into mathematically dependent shares (not just concatenated strings)
- Encrypting the mobile share with a one-time session key during transmission, so even intercepted data is useless to an attacker
Step 1: Reconfigure Secret Splitting
Ditch the simple P1 + P2 concatenation. Instead:
- Generate your GPG password, then split it into a 2-of-2 Shamir secret share pair (
S1andS2)S1: Store this locally on your host. For extra security, encrypt it with your host’s TPM (if available) or set file permissions to600(it’s completely useless on its own)S2: Store this only in your phone’s secure storage (e.g., your device’s keychain or a trusted mobile password manager)
Unlike concatenated strings, SSS requires both shares to reconstruct the original secret—one share gives zero actionable information about the password.
Step 2: Host-Side Unlock Initiation
When your host boots up:
- Launch your Cloudflared-proxied Python HTTP server
- Generate a unique session ID and random challenge string (for Ed25519 authentication)
- Create a one-time AES-256 session key (never reuse this for future unlocks)
- Encrypt the AES session key with your phone’s ECC/RSA public key (stored on the host)
- Send all three items (encrypted AES key, session ID, challenge) to your private ntfy topic
Step 3: Phone-Side Authorization & Encrypted Response
When your phone gets the ntfy alert:
- Confirm the ntfy topic is valid (use ntfy’s built-in password protection for your private channel)
- Use your Ed25519 private key to sign the challenge + session ID (blocks replay attacks)
- Decrypt the AES session key with your phone’s private key
- Encrypt your
S2share with the AES session key - Send back the signed challenge, encrypted
S2, and matching session ID to your host’s HTTP endpoint
Step 4: Host-Side Verification & Secret Reconstruction
On the host:
- Validate the incoming session ID matches the one you sent (blocks stale/replayed requests)
- Verify the Ed25519 signature using your stored public key (ensures only your phone can authorize)
- Decrypt
S2with the one-time AES session key - Combine
S1(local) andS2(decrypted) via Shamir’s algorithm to reconstruct the GPG password only in memory - Decrypt your
.envfile in memory (never write decrypted content to disk) using the GPG password - Launch Vaultwarden by passing the decrypted environment variables directly via the process’s environment (avoid command-line args—use Python’s
subprocess.run()with theenvparameter to keep secrets out ofpsoutput) - Immediately wipe all sensitive data from memory: overwrite variables holding the GPG password, AES key,
S2, and decrypted.envvalues (in Python, usectypesto zero out memory or explicitly overwrite strings)
Extra Hardening Tips
- TPM Protection for S1: If your Linux host has a TPM 2.0 module, encrypt
S1with it—this ensuresS1can only be decrypted on the physical host, adding a layer if an attacker exfiltrates your disk. - Session Timeouts: Set a 5-minute timeout on your unlock script. If no valid response comes in, wipe all temporary data and shut down the HTTP server.
- Script Permissions: Make your unlock script owned by
rootwith permissions700—no other user should read or execute it. - Process Isolation: Run Vaultwarden as a dedicated non-root user, and keep the unlock script running with minimal privileges only long enough to launch the service.
Why This Meets Your Requirements
- Remote Approval via ntfy: The flow uses ntfy to trigger and coordinate the unlock request, requiring your explicit phone action.
- Strong Device Authentication: The Ed25519 challenge-response ensures only your phone (holding the private key) can authorize an unlock.
- No Persistent Full Secret: The host never stores or retains the full GPG password—
S2is only decrypted in memory temporarily, and the AES session key is discarded immediately. - Resilient to Host Compromise: Even if an attacker gains root access and monitors traffic/memory:
- They can steal
S1, but it’s useless withoutS2 - They can intercept encrypted
S2and the encrypted session key, but can’t decrypt either without your phone’s private keys - Each unlock uses a new session key, so captured data from one session can’t be reused for future unlocks
- They can steal
内容的提问来源于stack exchange,提问作者Pandofla
相关产品推荐
相关产品推荐

