0x03: The Simplest Thing You Can Do To Secure Your App

It's so easy to not know, and yet so easy to do.

A hand resting by a USB key, which is inside of a generic laptop and has a key symbol on it.

Application secrets are a thing you might have known about, but maybe what they’re actually for is a bit of a mystery.

Django, for instance, tells you to keep the secret key used in production, well, secret.

But . . . why? What does that random value do for you?

Depending on what you’re using a secret value for, it could be anywhere from just making sure you don’t get rate limited using the Spotify API, to signing and encrypting your application’s session cookies, to allowing you to access your entire AWS cloud.

Speaking of that, in 2014, a hacker breached Uber and got access to an entire AWS cloud’s worth of data . . . all due to hard-coded creds. Yeowch.

Hard-coding your credentials is a common, if bad, habit to have. It likely stems from coding tutorials and just needing a quick and dirty way of getting an API integration or other app up and running.

However.

That source code may at some point end up on GitHub or some other repository site, and hopefully you intended it to be there. And if it is, then those hardcoded secrets are available to, oh, I don’t know . . . everyone?

I had my own scare with this in the past. In my first year of university, I created a script to log me into my university account because little old me didn’t know about password managers, or making browser extensions. So I made it with my actual password, and hard-coded the credentials in.

Then I got a tip from my much-more-security-oriented-at-the-time friend that maybe hard-coding my password and then pushing my code to a public repository wasn’t the greatest of ideas.

So, one password reset and a lot of developer experience later, I’m here to tell you exactly how you could be managing those random little strings that can potentially cause you major headaches if they get leaked.

1. Application Secret Keys: Random

This is probably the easiest thing to implement. I’m going to use Python as an example here, but many languages have their own cryptographic secrets modules.

Cryptographic secrets modules allow you to quickly and easily generate strong, cryptographically secure random . . . well, whatever you need! Numbers, byte sequences, hex strings, etc.

In our case, I’m gonna generate a totally random secret for some quirky little web framework that doesn’t exist. Originally, we might have had something like this in the app config:

# ---SKIPPED FOR BREVITY---APP_SECRET_KEY = "X_rVROKyeOnBoER76R4mEA"

We’ll use the secrets.token_hex() function to generate a 64-byte secret. That’ll be plenty of entropy!

import secrets# ---SKIPPED FOR BREVITY---APP_SECRET_KEY = secrets.token_hex(64)

That’s it! You can alternatively use the secrets.token_urlsafe() function for something not quite as long. The secrets module comes with Python by default, so no pip install necessary.

One problem with this: It’s not exactly the most helpful if we ever reboot our app (we’d have to re-login, we’d lose all JWTs or cookies, etc.) and it also doesn’t help for values we need to maintain. Hmm…

2. Secret Values: .env Files

A step up from this is leveraging environment variables inside .env files. These allow you to pre-define variables in a file and then load them into your app later. Useful for API keys, database URLs, and other access keys.

If you’re using version control, one way of doing this securely is just ignoring the actual .env file(s) you use, and using a .env template file that you keep in. It’s a bit hacky, but it works.

Let’s look at an example with a cloud provider that also does not exist. They give us an access token that looks a little something like this: ENDERCLOUD_NuvWvcDZ0Pc1oNyEW56wDB5cCQ-J2-ffnftmPbEL0-w

In order to have this with environment variables, we need two things, a .env file and our actual code. For Python, we’ll use the python-dotenv package.

For our .env file, we’ll specify our variable and our key value in the format <variable>=<value>:

ENDERCLOUD_SECRET_KEY=ENDERCLOUD_NuvWvcDZ0Pc1oNyEW56wDB5cCQ-J2-ffnftmPbEL0-w

Then, back to our totally nonexistent framework config:

from dotenv import load_dotenvimport osload_dotenv()#---SKIPPED FOR BREVITY---ENDERCLOUD_SECRET_KEY = os.environ.get("ENDERCLOUD_SECRET_KEY", None)

That os.environ.get snagged the environment variable right out of our environment, which was altered with that load_dotenv() call.

For the time being, that should cover you. But if you ever need secrets that can be securely managed by entire teams, that’s when I’d start looking at secrets managers like Bitwarden Secrets and Hashicorp Vault.

Don’t worry, though, that’s enterprise grade stuff.

Reply

or to participate.