System Background
Sensitive data must be stored (i.e. Credit Card number or SSN) in the system for a notable period of time, to serve ongoing operation of the company.
Anyone can insert sensitive data. Only specific users are allowed to retrieve.
Precautions taken in securing the application and auxiliary services. (i.e. HTTPS connection, install regular Security Updates, research/secure Authentication/Session Management, back-end SSH, securing the application as a whole against XSS, SQLi, etc, etc)
Encouraging secure practices on end-user PCs and Networks of the those Authorized to access sensitive data, but may not be able to enforce from the server-side.
The application is designed from the ground-up. (not a retroactive-security upgrade)
Encrypted data isn't always secure
I would think that any security expert would tell you to encrypt sensitive data (i.e. SSN or Credit Card numbers) on the machine, even during production, because even with appropriate precautions and a ground-up secure design, there is always a risk that somehow, the data could be leaked, or the server hacked, or the application exploited.
The problem I see with encryption, is that the server must also have access to the Key. While we can store this outside the SQL Database. Also this can be backed up on paper instead of the usual electronic archives. There are many possible attacks besides SQL-Injection or Backups theft in which case the Key would be stolen as well, defeating the encryption.
I envisioned a solution for Key Management some time ago but only today I am posting this as a question requesting professional feedback.
Solution, requesting feedback.
When an user account is Authorized to access/export sensitive data:
Password reset is required, with very high strength checks.
An Asymmetric (RSA) Key-pair is generated for the User. The Public key is stored in plain.
The Private User Key is encrypted using a Symmetric encryption derived from the user's (strong) password.
→ To access the Private User key for this User, you need to guess the user's password.
As usual, the password is saved with BCrypt, quite separately from Key Derivation.
Sensitive data is submit from a less-authorized user.
An Asymmetric Key-pair is generated for the Data. The Public Data key is stored in plain.
The Private Data key is encrypted using every single Authorized user's Public User key.
The sensitive data is encrypted using the Data key.
→ To access the sensitive data, you need to determine the private Data key, which is not stored directly, but can be accessed if you guess the password of an Authorized User.
The same Data key is re-used for up to 90 days.
Older keys are purged when no data is associated with them.
When an Authorized user signs in.
The sign-in is verified using BCrypt.
A Session Token is generated with at least 72 bits of entropy and passed to the browser.
The Private User key is temporarily decrypted (using Symmetric key derived from Password), and then re-encrypted for the current session. (using Symmetric key derived from Session Token)
→ To access the sensitive data, one can either guess a user's password, or steal the Session Token.
The server-side only stores a simple SHA-256 hash of the Session Token.
While signed in, the Authorized user's browser will pass the Session Token, which is used to decrypt the User Key, used to decrypt the appropriate Data Key, and then the Sensitive data can be served where appropriate.
So, supposing the server or database were compromised, an attacker would need to do the following to gain access to Sensitive Data.
- Guess one of the weaker passwords among the small pool of Authorized individuals, or
- Steal a session key from a machine currently in use by an Authorized individual
- Or, edit the operational software to begin storing the data in plain text (only possible if the intrusion provides Read+Write access)
It seems to me, this is the most robustly secure implementation possible.
A) Is this recommended?
B) Is this implemented in main-stream Libraries or Applications, or is this a rather unique idea?