0

I am planning on writing a web-based password management software, in order to provide sharing and permissions functionalities within team groups and members.

EDIT:

As mentioned below by Luke Park, I wanted to add that I am using a user-password authorisation with tokens (which expire). The token is provided on all authorised API calls making these calls only accessible by registered users. And yes, the application is wrapped by SSL making communication between server and client more secure.

END OF EDIT

Currently I have done a lot of research about finding a correct pattern for handling password encryption. The pattern that I am looking at is called Hybrid Encryption since it works with multiple clients and can be implemented securely. Here's how I would implement this pattern in my application logic:

CLIENT WANTS TO CREATE A PASSWORD

  1. Andre creates a password and provides the password as plain text
  2. The frontend app generates a symmetric key which is called session key
  3. The client encrypts the plain password with the session key
  4. Andre chooses to share the password to Bob
  5. The client retrieves the Bob's public key from the server application via REST
  6. The client encrypts the session key with Bob's public key
  7. Client transfers the encrypted session key and the encrypted password to the server

SERVER APPLICATION HANDLES PASSWORD SUBMISSION

  1. The server application encrypts the data with a private salt, which is only known by the server application
  2. Sever stores the data into a database

RETRIEVING SHARED PASSWORDS

  1. Bob requests Andre's recently shared password
  2. Server decrypts the requested dataset with the private salt and sends it to the client
  3. The client decrypts the session key using Bob's private key (which is provided by Bob's computer)
  4. Using the decrypted session key, the client can decrypt now the password (Now it can be copied for example)

So far, I see this pattern secure enough, since all private keys of the clients are not public and only visible to the clients. In order to implement this in a web-based application, I found openpgpjs.org which can generate public and private keys on client side and encrypt or decrypt data aswell using these keys. On top of that, private key strings can be protected by a secret passphrase.

My question is, how can I implement the private key file into my frontend application without messing up the user experience? I don't want to force the user to manage his private key manually and force him to provide the key on each password request. Is it secure to store the private key file into the browser's local storage and get the private key from local storage on each password request?

Dennis
  • 1
  • 1
  • 4
  • This is all fine. But to me the idea of storing my passwords in a web environment sounds ridiculous. – arkascha Jan 16 '16 at 21:49
  • As long as the encryption is secure enough, the fact that it is a web application does not affect the overall security significantly. Also, I am not planning to provide a SASS implementation, but rather a secure self-hosted application which can be managed locally for example. – Dennis Jan 16 '16 at 21:54
  • The issue with the web environment is that as a user there is no way for me to examine what I am using. Unlike with a locally installed utility I cannot check the code, since it is reloaded each time I access the utility. That is per definition a situation I cannot trust. "The web" is a fine thing. But it is _not_ a good replacement for just everything. – arkascha Jan 16 '16 at 22:01
  • I do agree with you on the trust factor, but this application has a very specific purpose and is not addressed on those people who wouldn't trust it. – Dennis Jan 16 '16 at 22:06
  • No one can trust it. :-) Except (maybe) the service provider. – arkascha Jan 16 '16 at 22:07

3 Answers3

1

You still have no way to verify your clients and server. Because anyone can publicly request public keys, it would be easy to MITM between a client and the server, and feed it a garbage arbitrary password.

Consider:

  • Attacker retrieves Bob's Public Key using REST.
  • Attacker generates their own "Session Key" and encrypts some arbitrary value.
  • Attacker feeds the result to the client, who has been Man-in-the-middled.
  • Client thinks it has received the correct password, but hasn't.

Without being able to verify and authorize both server and client, your system becomes easy to mess with. It may not seem like a huge problem, but it can easily make way for other attacks.

EDIT: Also noticed that if a MITM occurs between the client and the REST API, the attacker can feed the client a public key paired with a private key that the attacker owns.

Consider:

  • Client is about to share it's password with the server.
  • Client contacts the REST API (MITM Attacker) to pull Bob's Public Key.
  • Attacker supplies their Public Key.
  • Client generates Session Key and the ciphertext of the password.
  • Client sends the result to the "server" (the attacker).
  • Attacker uses their Private Key to retrieve the Session Key.
  • Attacker uses the Session Key to retrieve the plaintext password.
Luke Joshua Park
  • 9,527
  • 5
  • 27
  • 44
  • Thank you for pointing this out. However, I do use a user-password based authorization in order to access the application which generates session tokens on each login. Does this prevent the security issue that you have mentioned? I do think so, because the REST API Calls are not accessible in public. – Dennis Jan 16 '16 at 22:10
  • How are these user-password communications secured between client and server to access the REST service? You'll need to be careful, or else you'll just end up in an arms race. – Luke Joshua Park Jan 16 '16 at 22:14
  • @user3577183 Additionally, please see my edit above. – Luke Joshua Park Jan 16 '16 at 22:18
  • For now I have implemented a verifyPassword method on the server-api which will generate a JWT token with an expiration date. (https://github.com/auth0/node-jsonwebtoken is the library I am using). The access token can be later passed among the HTTP headers. Each authorized call checks whether the token has expired or is valid. – Dennis Jan 16 '16 at 22:18
  • @user3577183 But is this communication under some secure layer? SSL? Symmetric encryption etc? If it's plaintext then it won't fix the problem at all. – Luke Joshua Park Jan 16 '16 at 22:19
  • Once the application is finalised, the plan is to wrap the application under an SSL layer - so yes, it does. Regarding to your edit, I don't see the issue that you have pointed out. In order to access a password the hacker needs the session key generated by the original user which is only "decryptable" if Andre would have encrypted his session key with the hacker's public key. – Dennis Jan 16 '16 at 22:24
  • Oh, I see what you mean. Well, public keys in general are generated on client side once the user signs up. The public key gets transferred to the server and will be stored as reference to the user. In order to inject a different public key (like you have written in your example), the hacker would have to change the user's public key in the database. I think this is an aviodable situation if the REST API is working correctly, isn't it? – Dennis Jan 16 '16 at 22:35
  • @user3577183 They wouldn't have to change it in the server database if they MITM the client. They can generate their own Public/Private key pair and just pass their public key to the client. – Luke Joshua Park Jan 16 '16 at 22:37
  • Ok, I have misunderstood the concept of MITM. Thanks for pointing this out. As far as I can read from the wikipedia article, this is avoidable with several defense methods which can be added on top of the architecture that I have (such as DNSSEC). Am I evaluating this correctly? So a solution would be to ensure that the client is communicating with the correct server using DNSSEC. – Dennis Jan 16 '16 at 22:45
  • @user3577183 Technically yes, but your system is becoming extremely bloated quite quickly... You're making extra work for yourself really. – Luke Joshua Park Jan 16 '16 at 22:49
  • Any other suggestions then? Or is this supposed to be that complicated when trying to create a web application like this. All that I am looking for is just to encrypt passwords and share them to a specific group of users. – Dennis Jan 16 '16 at 22:51
  • @user3577183 Information security and cryptography **are** hard. The key is having a way to **verify** your information and **disguise** it at the same time. – Luke Joshua Park Jan 16 '16 at 23:01
  • I will keep all what you have said in mind, thank you. I can't mark your answer as solution, but I thank you for taking your time. – Dennis Jan 16 '16 at 23:07
0

After a couple of thoughts I decided to encrypt the RSA private key with the user master password. Since the master password is nowhere stored, I assume that it is safe to store the encrypted private key into the user's local browser storage. This solution makes it possible to automatically provide the encrypted private key on each password request, but forces the user to enter his password on each request, which is fine for me for now.

If anybody has a better solution, I would be glad if you can post your solution here.

Dennis
  • 1
  • 1
  • 4
0

Honestly, the whole 'using a session key as a symmetric encryption token' scenario seems a bit redundant to me. It will add a certain level of obscurity, perhaps, but the whole idea of passing encrypted data + encrypted token seems kind of odd to me.

I would try to reconsider the setup a bit as well. In the end, this is a web-based application we are talking about, wouldn't it be simpler to access this via ACL and privileges to the password?

Creating password

  1. Bob creates a password in plaintext
  2. The application encrypts the password with Bob's public key (obtained while logging in)
  3. The application saves the encrypted password through REST using JWT (obtained while logging in)

Retrieving password

  1. Bob attempts to view his password in plaintext
  2. The application makes a request to REST using JWT (obtained while logging in), requesting Bob's private key
  3. The application receives private key, decrypts the password, and displays it.

Sharing password

  1. Bob decides to share one of his passwords with Mark (let's say there is a magical button next to every password called SHARE WITH MARK)
  2. The application encrypts Mark's user token using Bob's public key
  3. The application sends a request to REST using JWT (obtained while logging in), sending Mark's encrypted user token
  4. REST application receives request, decrypts Mark's user token using Bob's private key
  5. REST application creates new RSA pair for Bob-Mark relationship where Bob is provider and Mark is receiver
  6. REST application creates new password under Mark's user token, encrypting it with this new RSA pair

TL;TR

Do not share passwords per se. Instead, invest some time into ACL and generate new RSA pairs for user pairs (provider + receiver). One step further would be creating special table for shared password - it will be cleaner and also will take some headache away when dealing with revoking privileges.

Jiri Kralovec
  • 1,487
  • 1
  • 10
  • 18