事件溯源(Event Sourcing)中密码修改的安全隐患探讨
Great question—this is one of the most common pitfalls when applying event sourcing to user management, especially for sensitive fields like passwords. Let’s break this down clearly:
First: Your Concerns Are Valid
You’re absolutely not overthinking this. Storing historical password hashes (let alone plaintext) in immutable event streams creates unnecessary security risks, even if you’re using strong hashing algorithms. Here’s why:
- Event stores are designed to be permanent and immutable, so any sensitive data you put in there stays forever.
- Even strong hashes aren’t immune to future brute-force attacks (as computing power grows) or targeted attacks if an attacker gains access to the event store.
- As you noted, user password reuse across platforms turns historical password leaks into cross-platform risks—this is a real threat, not a hypothetical.
Is This the "Common" Approach?
No, storing full historical password hashes in event streams is not a standard or recommended practice. The core conflict here is:
- Event sourcing requires permanent, immutable records of state changes.
- Password security requires that we only keep the current, strongly hashed password (and never historical ones).
These two goals don’t have to clash—you just need to separate concerns appropriately.
Standardized Solutions
Here are the industry-standard ways to handle this:
1. Separate Sensitive Credential Storage (Recommended)
This does not violate event sourcing principles—hear me out:
- Event streams should record business state changes, like "user updated their password" (a fact about the user’s account activity), but not the sensitive credential itself.
- Create a dedicated, secure storage system (e.g., an encrypted database table with strict access controls) to store only the current, strongly hashed password (use Argon2id, BCrypt, or PBKDF2 with a unique salt per user).
- When you publish a
UserPasswordChangedEvent, it only needs to signal that the password was updated (no hash included). Your authentication service will fetch the latest hash from the dedicated storage when needed.
This approach keeps your event stream focused on business facts (the core of event sourcing) while respecting password security best practices.
2. If You Must Include Hashes in Events (Not Recommended)
If for some reason you need to tie password hashes to your event stream (e.g., for audit purposes with strict compliance rules), do this:
- Never store plaintext or weak hashes—only use state-of-the-art hashing algorithms with unique salts.
- When replaying events to build a user’s current state, explicitly ignore all historical password hash events and only retain the most recent one.
- Add an extra layer of security: encrypt the hash field in the event using a key management system (KMS), so even if the event store is compromised, the hash is unreadable without the decryption key.
3. Encrypt the Event Store (Defense in Depth)
Encrypting your event store (either at rest with transparent data encryption, or field-level encryption for sensitive fields) is a good security practice, but it’s a complement to the above solutions—not a replacement. It adds overhead, but it’s worth it as part of a layered security strategy.
What About Strong Hashing Alone?
Even with the strongest hashing algorithm, retaining historical password hashes is still risky. Here’s why:
- While algorithms like Argon2id are currently unbreakable with modern hardware, future advances (e.g., quantum computing) could change that.
- If an attacker gains access to the event store, they can precompute rainbow tables or use cloud computing to brute-force hashes over time.
- Users often reuse passwords, so even an old, hashed password could give attackers access to other accounts the user owns.
Final Takeaway
Your second proposed approach (events signal password changes, passwords stored separately) is the right way to go. It aligns with event sourcing’s core value of tracking business state changes while prioritizing security. Encryption of the event store can be added as an extra layer of protection, but separating credential storage is the foundation.
内容的提问来源于stack exchange,提问作者filpa

