Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

where to store SHA256 key pair per user

I have a database and an API in NodeJS, I create users with web app, and each user can create/update/delete data.

To secure this a bit, I need to encrypt data of users. So what I want is creating a pair of SHA256 public private keys each time a user is created.

Actually what I do is storing thoses keys in database, by encrypting them with global SHA256 pair of key.

So, in a nutshell, I have a global pair of key to encrypt each specific pair of keys for each user.

The fact is that seems to be not really secure because finally each user have his own encryption/decryption method stored in the database.

For example I can have 2 tables :

User table :

id_user | firstname | lastname | encrypted_data
-----------------------------------------------
1       | John      | Doe      | QMwmuCMmI..
2       | Jane      | Doe      | QMwmuCMmI..
... 

Keys table :

id_user | public    | private
------------------------------
1       | MIICIjA.. | MIIJrT..    
2       | MIICIjA.. | MIIJrT.. 
...   

So the link from John Doe to his public and private keys in simple.

A problem is that I can't ask for user to create a pair of private/public key and send me only public, because all need to be automatic, user don't have to do anything.

Another problem is that the application should be usable on any device, so the private key can't be stored in client side.

like image 813
Alexis Avatar asked Apr 11 '21 16:04

Alexis


2 Answers

You can't just store them on the server as the attacker is on the server. The malicious hacker can easily find the keys (as they are un-encrypted), download the entire database and decrypt everything.

So, your best options are storing the keys on a completely different machine and let that machine do the encryptions and decryptions. That way the attacker would first have to break into your machine, and then the extra step of into the encryption/decryption machine. Not impossible, but hopefully much harder.

Basically, nothing is un-hackable. Making something as difficult as it can be for the attacker is the way to go.

Also, even if you strictly have to store the data in a database that your main server has access to, do NOT store them in the same table (as shown in your example how you kept them in separate tables). Keep the indexes of all data added to the user database the same, so that index 1 of users database will result in the correct key for that index (exactly what you did).

Another option would be cryptographic hardware. I'm not familiar with this, but I do know that some companies sell hardware that perform all of your cryptographic needs.

like image 144
divinelemon Avatar answered Oct 13 '22 22:10

divinelemon


Disclaimer: This answer exposes two solutions to secure user data, but exclude SHA256 public/private keys from the equation (for, I believe, something more secure). It might not be an acceptable solution.

The "easy" way

I believe it's how Termius does it. In this case you would use the password to secure both the account access and encrypt data.

You would end up with something like that in database:

  • id
  • email/username
  • password_hash (to secure the account access)
  • ... as many fields as you want, values are encrypted using a symmetric algorithm (i.e. AES) using the unhashed password

Advantage:

  • (optional) end-to-end encryption
    instead of doing the decryption server-side, send the encrypted data as-is to the client. It will be the client app responsibility to do the decryption before the visualization, and to encrypt everything before sending it back to the server.

Drawbacks:

  • potential data loss
    if an user loose its password, he also looses access to all its data.
  • the encryption key is stored in the database
    sure, it's hashed. If the hashing algorithm is strong enough, it could be enough security for quite some time. But for some 3 letters agencies, it might be reversable relatively fast 🤷‍♂️

Warnings:

  1. don't use the password hash as the key, only the unhashed password. Otherwise, the encryption key is stored "as-is" in your database (the password_hash field).
  2. always use a salt when you compute passwords hashes (might sound obvious to say this in 2021, but still, I prefer to say it)

Even more robust encryption

I believe this is the way ProtonMail encrypts its users' data.

When you create a Protonmail account, you need to provide two passwords: the first one is used for account login, the second one for data encryption.

Advantages:

  • you don't need to store the second password in your database at all (hashed or not).

If the data can't be decrypted, it means the second password (aka the encryption key) is incorrect, its as simple as that.

  • (optional) end-to-end encryption
    same as described in "the easy way".

Drawback:

  • potential data loss
    if an user looses its second password, he also looses access to all its data. If he looses its first password, then he just looses access to "authentication". The typical "I forgot my password" flow works here, without raising any issue related to the encrypted data.

Measuring the pros and cons

Both solutions have a main drawback: potential data loss.

If you go for the Protonmail-like solution, I would say this drawback is compensated by a major advantage: the user is the only actor of its data's security, you store no hints about the encryption key in your database. Therefore, if you use industry-standard encryption algorithms you aren't responsible at al. Hackers would have no solution other than brute-forcing the encryption key of every user, one by one.

Plus, if you educate your users about the consequences of loosing their password, you can also claim that you are 100% unable to access their data at the same time. This is the highest possible level of data privacy, and this is what the world needs IMHO (no matter what type of data we are talking about).

like image 1
abidon Avatar answered Oct 14 '22 00:10

abidon