5

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:

enter image description here

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.

ChristianF
  • 163
  • 5
  • The largest attack surface is the frontend, not the backend. How are you securing the frontend? – ThoriumBR Dec 02 '21 at 09:53
  • 1
    WRT the process when a user requests a password: `The password data is then sent back to the client web browser in a plaintext format, but protected in transit using HTTPS` - if I am reading this correctly, it seems that at that moment, your server has knowledge of the user's plaintext password. Many users may not be comfortable with this. What might be better is a solution where the password is encrypted/decrypted at the client side (i.e. in-browser, using client-side javascript), where your server only sees encrypted passwords and has zero-knowledge (or zero-access) of plaintext passwords. – mti2935 Dec 02 '21 at 18:22
  • 1
    Thanks for your comment @mti2935. You are correct that in that instant, the server has access to the plaintext password. If I'm understanding correctly, client side encryption is beneficial if the server is not trusted by the end user. However, does the solution of C.S.E. not just kick the problem down the road a bit? If the server is not trusted, then the JavaScript that it sends to clients to handle decryption can't be trusted. I might be misunderstanding the threat model here. I suppose the benefit is that the client side code can be audited by any user to check for malicious behaviour? – ChristianF Dec 02 '21 at 22:13
  • 1
    @Chris, That's an excellent question. This problem is sometimes referred to as 'the browser crypto chicken and egg problem'. See https://security.stackexchange.com/questions/238441/solution-to-the-browser-crypto-chicken-and-egg-problem for some interesting reading (and possible solutions) around this problem. Notwithstanding, this problem doesn't seem to have hindered adoption of other zero-knowledge systems using browser crypto, e.g. protonmail, sync.com, 1password, etc. – mti2935 Dec 02 '21 at 22:44
  • 1
    @mti2935 Thanks very much for the reply and introducing me to the 'browser crypto chicken and egg problem'! Very interesting. It looks like some of the best providers in the password management space are all using the zero-knowledge approach (1password, bitwarden, etc.), so I'll be taking that route with the design of my system - I can definitely appreciate that a service provider never has access to plaintext data of clients. BTW: if you'd like to put any of your comments into an answer I'd be happy to accept it. Cheers and thanks again. – ChristianF Dec 04 '21 at 02:28
  • 1
    No problem, @Chris. DONE. Good luck with your project! – mti2935 Dec 04 '21 at 12:13

1 Answers1

1

Here are a few take-aways after some back-and-forth with the OP in the comments:

  1. In OP's model, users' passwords are encrypted and decrypted at the server. This means that the server has knowledge of these passwords at the moments that they are encrypted or decrypted. Some users may not be comfortable with the server having knowledge of their passwords, so a 'zero knowledge' (or 'zero access') model was suggested, where passwords are encrypted and decrypted at the client side (in-browser), using javascript crypto.

  2. This leads to another problem - the browser crypto chicken-and-egg problem. The user must now trust that the browser crypto code served by the server works 'as advertised'. A malicious server could simply serve client-side code that captures the user's plaintext password, and sends it back to the server. If the user doesn't trust the server with its secrets, then how can the user trust the server to serve secure crypto code?

See Solution to the ‘Browser Crypto Chicken-and-Egg Problem’? for some interesting reading about the 'browser crypto chicken and egg problem', and some possible solutions around this problem.

mti2935
  • 21,098
  • 2
  • 47
  • 66