I'm designing a password vault that's accessible to clients through an existing web application. The clients are small, (and mostly non-technical) businesses that aren't using password managers, but are using this existing application that the password vault will be added to. The goal of this (sub-)system is to securely store credentials for businesses that typically need to be accessed by multiple internal parties (e.g. the business owner and internal accountant).
I've built a model of how this could work and I'm looking to get some feedback on the security aspects of it.
Passwords are entered as a key -> value pairs such that the key is a description of what the password is for. There are multiple values: the url where the password is usable, the associated username, and the password itself. The key (which is a description of what the credentials are for e.g. a website name) is stored in plaintext, while all values are encrypted. This data is stored in a MySQL database, running on a server only accessible by the application servers or key-based authentication.
When a business sets up the password vault for the first time, a master password is entered by the business and stored for the company in a MySQL DB after it has been hashed using bcrypt, with a cost of 15 (32,768 internal bcrypt iterations).
Next, a business can store a key -> value(s) credential pair. The values for the given key (password, associated URL, username, etc.) are encrypted using AES-256-CBC to provide confidentiality of data at rest.
Next, the values are signed using a HMAC (SHA256 hash of the AES initialization vector, concatenated with the ciphertext, passing in the derived secret key from PBKDF2 to the library function used to generate this digest), in order to ensure integrity of the data at rest (e.g. if the ciphertext were to be modified, the MAC verification would fail and a decryption exception would be thrown in my application, so that an incorrect plaintext password would not be sent back to the client).
The secret key used for AES encryption/decryption is generated using PBKDF2 (via OpenSSL). I have configured PBKDF2 to complete 100,000 iterations, as well as apply a 32 byte salt (which is stored in the DB, and generated using a function that returns cryptographically secure pseudo-random bytes), and to use SHA256 as the cryptographic hashing algorithm. This secret key is generated when a request hits my web application which needs to encrypt or decrypt the stored data. The password data is then sent back to the client web browser in a plaintext format, but protected in transit using HTTPS. The master password is stored in the session of the user so that it needs to only be entered once per session, in order to increase the usability of the system.
The overall system/network architecture is as follows:
Note that to the left of the line in the picture is the data centre. I'm assuming that this network can be trusted, and TLS terminates at the load balancer. All application servers and databases are located within the same data centre, and access one another using their private (non-routable) IP addresses.
The limitation of this system is that there is no way to reset a forgotten master password. I am OK with that, and will be recommending to businesses that if they are worried about forgetting it, that they could write it on a piece of paper and store it in a physical vault in their business (mostly restaurants, breweries, bars, etc., so physical vaults are quite common). A password hint option is also available.
Question:
Given the above design, what potential vulnerabilities or security problems do you see?
I'm probably going to hire an application security firm to look at things as well (given the potential severity of making a mistake while building this) but I thought I'd ask here first. Cheers!
Note: might opt for using AEAD (e.g. AES-256-GCM) instead of cipher block chaining mode.