4

I'm building an application, part of which will allow businesses to store secrets.

I'm looking at using CryptoJS (https://www.npmjs.com/package/crypto-js). This would encrypt everything on the client side, and send it to the server-side using HTTPS before it is saved to our database. No plain text secrets would ever be received by our server or stored in our database.

From CryptoJS's documentation:

var CryptoJS = require("crypto-js");

// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();

// Decrypt
var bytes  = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);

console.log(originalText); // 'my message'

We would prompt the user to provide a decryption key (in the example above 'secret key 123'), which we'd put some requirements on such as minimum character length, including a number, special character etc.

From a security perspective, do you see anything wrong with this setup, considering the use-case?

Some previous people have suggested looking into HashiCorp's Vault, which I've already done and got it working as a proof of concept, but the price is too high for this use-case (estimated the cost to be ~$150 per company, per month on their standard plan for a Managed HashiCorp Cloud Vault, and we don't want to self-host our own vault server).

vue-coder
  • 143
  • 3
  • AFAIK, the crypto-js library is out of date and the included crypto should be used. Someone please correct me if I'm wrong – Sir Muffington Oct 09 '21 at 23:10
  • It looks like crypto-js is still under active development (last release was on Aug 11 it looks like) - but I'm not super familiar with it. In terms of something included (in the browser?), are you suggesting OP uses something like https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto? – ChristianF Oct 09 '21 at 23:19
  • 1
    Hey, just want to point out that bitwarden is open source, and there are much more lightweight open source compatible alternatives, like vaultwarden. They have user management, allows to save encrypted files, texts etc; it might fit your needs. – hytromo Oct 10 '21 at 07:34
  • Related: https://security.stackexchange.com/questions/238441/solution-to-the-browser-crypto-chicken-and-egg-problem – mti2935 Oct 11 '21 at 22:28

2 Answers2

9

Potential issues:

  1. What kind of client are you envisioning? If it's web-based, or anything else that pulls code (scripts, etc.) from the server, it's ~impossible to make it secure against a malicious or compromised server. The attacker simply sends an additional script - possibly only to specific targeted users - that steals the passphrase, encryption key, plaintext secrets, or anything else desired.
  2. How does the user authenticate to the server? If it's via a password, does that mean they have to remember two passwords to use your app? If it's the same password, you need to make sure that it's not possible for the server to ever see, or derive, the password.
  3. Do you have any plan to handle forgotten passwords in any way? Systems like this one often have a very hard time with that problem.
  4. Do you have a plan for a user changing passwords that doesn't require decrypting every item and re-encrypting it with the new password? The usual approach is a layered system, where there's a "master key" used to actually encrypt/decrypt the data, and which is itself encrypted using the password-derived key (this way, it's only necessary to re-encrypt the master key, not everything).
  5. Is there any data processing (e.g. search, analytics, any form of transformation or analysis) that you want to do server-side on the data? That won't be possible with a system like this.
  6. Do you want to support securely sharing data with other users? That can be done, but you need to use public key (asymmetric) cryptography for it, and if you don't want users to need to trust the server then they need to be able to verify the other party's public key.
  7. How are you going to protect the integrity of the encrypted data? Encryption by itself does not prevent tampering with the data.
  8. Are you doing anything to protect against padding oracles? The system as described isn't obviously trivially vulnerable to them but if you're using CBC with PKCS7 - which are the defaults for that library - you need to consider them.

On a more general concern level: respectfully, you don't have the knowledge necessary to design a system like this. It shows up both in things like the above topics being left unaddressed in your design, and in some of the things you said you were planning to do (a few examples: passing the library a user-supplied string rather than deriving a key from it yourself, using the default cipher parameters even though there are better ones [though that library doesn't support some of the best], requiring "a number, special character etc." as though that's anything other than pointless and plausibly-harmful security theater, using a third-party JS crypto library instead of the one built into modern JS engines including browsers).

CBHacking
  • 42,359
  • 3
  • 76
  • 107
1

If your requirement is asking user for a key/PIN/Password (you will have to hash it to use for AES Encryption), every time user wants to access his secret data and encrypting and decrypting in browser then, yes, this may be a good design depending on your security requirements.

Having said this, Chris, in his answer is pointing to SubtleCrypto. Navigating to the link has bold warning at the top. Are you sure your users will never forget key/pin/password for the secret, otherwise, you are going to lock their content permanently. If users are required to store their keys to remember; again it is a security issue depending your users security requirement and threat perception.

Better design would be to use keys stored in smartcard or cryptographic usb token and then use PKI with public key stored on server and private key in users smartcard. Refer to my SO answer

Bharat Vasant
  • 284
  • 1
  • 8