We’ve seen many different ways to hide secrets in source code. None of them are valid. It didn’t matter how hard the developer tried to hide the password, token, or key. We always managed to find it and compromise their system.
Let’s take a look at a few examples of how you can try to hide a secret in application code. We’ll illustrate why it’s always a bad idea as we go.
Ways to Hide Secrets in Code
Put the Secrets in the Source Code
The most obvious place to hide secret information in code is to just hard-code it right in place. There are several ways to add a string or number as a constant, depending on the language you’re working in. Define it in a string table or header file. Or, code it as a local variable next to where it’s needed. If you work with a compiled language like C++ or Java, you might tell yourself that it’s converted into a value that you can no longer see.
You can also dump a process from memory and analyze the results. If you’re (un)lucky, the secret is right there in memory, already decoded for you.
Secrets in source code are not secure.
It Can Get Even Worse
Is your code accessible via a web server? If your answer was no, are you sure? Web servers suffer from bugs too. This one makes it possible to view chunks of process memory with a properly crafted web request. This isn’t the first time a bug like that appeared in a web server, and it won’t be the last.
You can’t prevent bugs like that. Your web application is at the mercy of the flaws that your web platform suffers from. But, you can make your code safer by not hard-coding secrets in it.
Are you writing client-side scripts with secrets embedded in them? If you are, you’re distributing them to clients in plain text. Oops.
Hard-coding secrets in source code creates other problems, too. What happens when it’s time to update them? You do have a schedule for rotating secrets, right? You’ll have to build a new version of your application and deploy it. Will the extra work and risk make you less willing to change the secret? If you need to change a secret outside of your regular release schedule, will you skip it? Will you keep a potentially compromised secret in place because deploying a new release poses an even higher risk?
Depending on the nature of a secret, it might differ depending on location. What happens to a hard-coded secret if you need to deploy an application to a new site? Will you lower your security posture even more by trying to use the same secret in two places?
While we’re on the subject, why are you hard-coding anything in your source code? We’ve gone over the maintenance issues associated with hard-coded secrets, but most of them are true of any hard-coded value.
Home Brew Encryption
Maybe you’re smarter than the average bear, and you’ve figured out a way to obfuscate the secrets. Instead of including them directly in your code, you’re using encrypted values. Your application decrypts them in place before using them. So, the secrets are still there, but the bad actors can’t read them!
Yes, they can. If you found your method for decrypting the secrets on Stack Overflow, the bad guys have seen it already. If you made up a new one, it could be hacked, too. Unless you’re working in the wrong field and created new proprietary unbreakable cryptography in your spare time, it can be broken.
What you’re doing is spending time trying to patch bad practices with halfway measures. Instead of figuring out new ways to hide things where they don’t belong, put them where they should be.
We developers thrive on adding new levels of indirection. After all, abstraction and polymorphism are two of our most powerful tools. So, if you squint, putting your secrets in an encrypted package and hiding the key in your app code might look like an excellent alternative to hard-coding them.
Of course, there’s still a secret in the code. And if you can find that one key or token, you can use it to get the rest all of them. All you’ve done is put them in a nice, neat package.
We’ve looked at a few different ways to hide passwords, tokens, and keys, inside application source code. None of them are viable options. Maybe you’re already looking at the next step; get the secrets out of the source and put them in the runtime environment.
So, pass the secrets to your app as environment variables, right? This gets the secrets out of your source and solves maintenance issues too since they’re easier to change.
Environment variables, just like any other plain text configuration mechanism, can be read if you have access to the system the application is running on. They’re just as easy to compromise as secrets in source code, if not easier.
I already mentioned process dumps. They give you access to everything, including environment variables. If your application is running on Linux, you don’t even have to dump the entire process. The root user can view any running process’ environment on the command line.
Secrets in Git
If you’re embedding secrets in your code, management scripts, or configuration files, you’re checking them into source control, too. If you’re building packages with embedded secrets and then running them through source control as part of continuous integration (CI), you may even be checking them in more than once.
You should consider these secrets burned.
If you’re using a private repository (or even a private git server) you’ve added at least one additional vector for potential attackers. If you’re using git integrations, like a CI server or code review app, you’ve exposed all your secrets via yet another path.
How to Manage Secrets in Source Code
Don’t. They don’t belong there.
Your application secrets belong outside of your application code. Use a credential store or vault to offload your secrets away from your code, your source control, and your deployment tools.
Application secrets are more than configuration parameters or hard-coded strings. Treat them as artifacts that are managed, maintained, and versioned on their own.