Let’s say I have some sensitive data, e. g. an API key users have to add. I now want to send this key to the server and prevent any man-in-the-middle attacks. I’m using HTTPS for the communication, but I’m not sure if this is “enough” in such a scenario.
Would you recommend adding another encryption layer that is only known to the client and the server, and if so, what is the best way to implement this? The server should still be able to decrypt the key when needed.
API keys and other passwords are usually set as environment variables, that are only serverside. For example, here is adding some new environment variables at various platforms:
If there is some need to copy some environment variable to clientside, it’s possible by setting public variable:
Or if that environment variable is only needed serverside, it can stay at environment varible, or copied to private variable like Meteor.settings.headerLoginId .
API keys are usually needed to exist unencrypted at serverside.
3) User accounts
For user accounts, Meteor accounts packages save password in hashed format to database.
Before showing any sensitive data, it’s useful to check is user logged in:
if (Meteor.user()) {
...
}
4) Admin Panel
If at Admin Panel UI it’s needed to save some new password to database, it’s useful to just save it, for example with Meteor Method, but not load it back, not adding it to PubSub minimongo content.
import CryptoJS from 'crypto-js'. // this library is now deprectated but ... "Nowadays, NodeJS and modern browsers have a native Crypto module. " - Check the NPM details.
const passphrase = process.env.PHRASE // or your safe way to store a pass. This can also be a userId, session id, anything that you can pick up on the server for the same user. The userId can also be altered at both ends so that you cannot reverse engineer it.
return CryptoJS.AES.encrypt(string, passphrase).toString()
Decrypt
import CryptoJS from 'crypto-js'
const passphrase = '' // same as above
const bytes = CryptoJS.AES.decrypt(string, passphrase)
return bytes.toString(CryptoJS.enc.Utf8)
You can generate a key pair: Public key + Private key.
Send the Private Public key to client, client will use this key to encrypt data then send to server.
On the server side, use private key to decrypt the data.
// Edit: Send the public key to the client, not the private one.
Thanks. What is a good library to use for encryption on client and decryption on server side?
Do you happen to know how Meteor does it when sending the password to the server on sign up?
I saw that Accounts.createUser() also exists on the client. Unfortunately, it automatically logs the user in on completion. In my current use case, I want to create an admin interface that allows you to create new users.
I believe Meteor doesn’t send raw/plain password to server. It send sha256 hash instead. So in worst case, some how they intercepted your connection, decoded ssl/https encryption and got this hash, they can use that hash to login.
I use node-forge npm package to generate key-pair, encrypt and decrypt. It’s big package though.
Thanks. I had a look at the code of meteoreact:accounts and learned that you can actually send a hashed password as an object with the properties digest and algorithm using Accounts._hashPassword().
Fun fact: the TypeScript type annotations of Accounts.createUserAsync() do not know about this “password object” syntax, although the server does. So I am not sure if this is a somewhat “undocumented feature”, too.