With any salt/hashing, encryption/decryption a key is needed (or should be used). This key is something that needs to be protected, but it can be difficult to hide while still making it available.
I ran into this issue with the Password Manager that I created and for my Rails backend I could have an .env file to make my own key and keep it from being uploaded to my GitHub and I was even able to hide it within my host in a separate file that was not available to the public. Cool. This hides the key in the backend BUT what about the frontend?
The frontend is a bit more difficult to hide the key(s) because we need it to be available to encrypt things before they are stored in the backend, but also secure and not stored in the browser for another website to sniff out. This means that it shouldn't be stored in any local or session Storages within a browser.
But where to put them then???
For my project I would love for each user to choose their own key for everything or be able to set a key for each item they save. (Now, as my project is technically done, this is not a high priority but it is something that I want to continue learning about and working on.)
So let's look into better way of hiding keys from prying eyes.
If you choose your own key you need to make a proper key. If you chose to make your own then this is similar to making a good password. You can also choose to have one randomly generated but for my project I wanted to make one.
Some general rules for making your own key (or password in general) are...
- Never use your name, your dog's name, ANYONE'S name, or part thereof.
- Never use any part of your telephone number, address, or any other identifying information about yourself.
- Never use a properly spelled common word or proper noun.
- Never use a key shorter than ten characters.
- Never use the same encryption key and/or password for different services.
- Never use the brand of your favorite car, horse, motorcycle, vacation spot, etc.
- DO use a key with more than ten characters. The more the better.
- DO use a key with mixed letters, numbers, and special characters.
- If you use actual words, misspell them... badly.
- Add unnecessary punctuation marks to the middle of actual words or phrases. (1)
For my project I chose a passphrase and then modified it. It's backwards in some parts, forwards in others, I shifted characters depending on the character, it's about 20 characters long, and it has not been found in Have I Been Pwned. (Woot!)
I chose two different phrases for my current set up of frontend and backend. In the long run I will need to make the frontend more dynamic for each user and maybe each credential that they are saving, BUT for now this works for an introduction to keeping keys secure while deploying them.
As stated earlier... this part is easier, so far. For my project I could create an '.env' file and GITIGNORE it or hide it in my host, Heroku. Cool.
I followed these steps:
- In config/application.rb, add Dotenv::Railtie.load below Bundler.require(*Rails.groups), but above module .
- Add .env file to the root level of your app, with your keys in the following format, no spaces between equal signs: API_KEY_NAME=API_KEY.
- ADD YOUR .env FILE TO YOUR GITIGNORE!!!
- Just to reiterate, make sure to add your .env file to your .gitignore file. This whole process is pointless if you miss this step.
- .env values can now be accessed in your controllers via the ENV syntax.
- Create new controller methods & routes to correspond with fetch requests from the front end. (2)
This is not an end all of how to do it, but it's what worked for me.
After spending some time researching now other password managers keep their keys for encryption secret I discovered this...
It's just a lot of encryption on encryption on encryption.
Seriously though, this is how they do it.
PBKDF2 SHA-256 is used to derive the encryption key from your master password. This key is then salted and hashed. The default iteration count used with PBKDF2 is 100,001 iterations on the client (this client-side iteration count is configurable from your account settings), and then an additional 100,000 iterations when stored on our servers (for a total of 200,001 iterations by default). (4)
After speaking with a security engineer about the issue it is apparent that this is how it's done all over. The only other options are things like 2FA(two factor authentication) or a key that is related to the device itself. This could be something related to the environment that the application is running on.
How you handle keys in your frontend or backend is up to you really and though I would love the idea of a 2FA on everything, this isn't always the most ideal way to do things depending on the information that is being secured. We need to really consider the user and their experience and if it might become inconvenient and cumbersome to have to constantly be sent an authorization code to log into an application or website.
Here is something to ponder too... more encryption doesn't mean information is more secure. It just means that it is more annoying to get out if it's really wanted, not impossible.