Why is passing the secrets via environmental variables considered "extremely insecure"?

7,070

Solution 1

extremely insecure and should not be used. Some versions of ps include an option to display the environment of running processes. On some systems, if you set MYSQL_PWD, your password is exposed to any other user who runs ps.


This was explained here (via):

Background: in the process image argv[] and envp[] are stored in the same way, next to each other. In "classic" UNIXes /usr/bin/ps was typically setgid "kmem" (or similar group), which allowed it to dig around in /dev/kmem to read information about the active processes. This included the ability to read the process arguments AND the environment, of all users on the system.

These days these "privileged ps hacks" are largely behind us: UNIX systems have all come up with different ways of querying such information (/proc on Linux, etc) I think all(?) of these consider a process's environment only to be readable by its uid. Thus, security-sensitive data like passwords in the environment aren't leaked.

However, the old ways aren't 100% dead. Just as an example, here's an example from an AIX 5.2 machine I have access to, running as a non-root user

[AIX 5.2 reached end-of-life in 2009. AIX, at least by 6100-09, and also confirmed on 7.2, now prevents non-root users from seeing the environment of other users' processes with the "ps ewwwax" command.]

...

For the record, some while back we discovered (on IRC?) that OpenBSD 5.2 has this exact security exposure of leaking the environment to other local users (it was fixed shortly after that release, though).

[OpenBSD 5.2 was released in 2012]

This does not explain why the MySQL manual considered that using an environment variable is extremely insecure, compared to a command line argument. See the other answers to this question. In short, either the manual is confused, or the point is that it can be too easy for environment variables to be "leaked" by mistake.

Solution 2

This advice in the MySQL documentation is poorly worded.

Passing a password in an environment variable is not less secure than passing it on the command line, on the contrary. Most modern unices expose command line arguments of processes, but not their environment, to all users through the ps command and other similar software. There are exceptions, but I've never heard of a system where it is the opposite (exposing the environment without exposing the arguments).

Including a password in a command that is typed in an interactive shell is a bad idea because the password ends up in the shell history. It's fine if shell history is turned off but you have to remember to do that. This applies whether the password is passed as an argument or in the environment.

What can be more dangerous with environment variables is if the variable is passed to other processes. For example, setting a database password in .profile would be a very bad idea, since it would be visible to all programs. Likewise running a script with export MYSQL_PWD=… near the top that runs many commands beyond mysql would be a bad idea. But if the environment variable is only passed to mysql commands then there's nothing wrong with that.

The MySQL documentation should not use language that rates passing a password through an environment variable as less secure than passing it through a command line argument. It's the other way round. (Unless the environment is set for more than the mysql command but that isn't the scenario described in the documentation.)

Solution 3

The main issue with passing secrets in environment variables is to properly scope that environment to the process that use this secret, and to not give it to processes that should not have it.

It is secure to set an environment variable only for starting a given process that uses it.

But it is not secure to set secrets in environment globally in your shell (for the current session) (and even worse in the global startup files of the shell (.bash_profile, .bashrc, .profile)) because all process launched from that shell will have this secret in their environment. Some may leak them, either on purpose (malware) or not (think about the shell command history or a crash reporting module that dumps the full content of the environment in a log file or on a remote server).

Unfortunately from an application developer point of view, it is impossible to enforce that users of your application will properly scope the environment. I have personally seen so many secrets stored in ~/.profile.

So to avoid bad use of the environment by users, it is safer to not load secrets directly in the environment (to reduce the impact of a leak), and instead use environment variables to pass links to where the secret is really stored: use an additional layer of indirection.

Share:
7,070

Related videos on Youtube

Miloš Đakonović
Author by

Miloš Đakonović

Web (HTML5/JavaScript, PHP) developer. System administrator. FOSS (mainly Linux and Postfix) advocate.

Updated on September 18, 2022

Comments

  • Miloš Đakonović
    Miloš Đakonović over 1 year

    Passing secrets (password) to a program via environmental variable is considered "extremely insecure" according to MySQL docs and as poor choice (from security aspect) across other resources.

    I would like to know why - what is it that I'm missing? In the mentioned MySQL manual(I'm using this as an example), passing password via -p option in command line is considered as "insecure" and via env var as "extremely insecure", bold italic font.

    I'm not an expert but I do know the fundamentals: simple ps command, even issued by unprivileged user reads every program alongside with command parameters while only the same user (and root, of course) may read environment of the process. So, only root and johndoe may read environment of the johndoe - started process, while hacked www-data script reads all via ps.

    There must be some big deal here that I'm missing - so please explain me what am I missing?

    My objective is to have a mean of transferring secret from one program to other, generally, non-interactive.

    • Pankaj Goyal
      Pankaj Goyal almost 7 years
      Using mysql -ps3cret puts your password into your shell history file in plain text. Using a script or other means to put your password into an environment variable means that the password (or the means to expose it) is in that script, or if you export mysqlpasswd=s3cret, that will again simply add your password in plain text to your shell history.
    • Centimane
      Centimane almost 7 years
      @DopeGhoti if you place the export command into a script and source the script the password would at no time be in your history. The script could only be readable by your user. Using an environment variable properly will keep it out of your command history. The concern is not your command history, it's that the process itself might expose the evaluated argument to tools like ps.
    • Pankaj Goyal
      Pankaj Goyal almost 7 years
      You place the export into a script and your password is now in plaintext on disk, which is also a very poor choice.
    • Miloš Đakonović
      Miloš Đakonović almost 7 years
      @thrig , good point, I've taught of that.
    • Centimane
      Centimane almost 7 years
      @DopeGhoti read -p "Input mysql password: " pass ; export mysqlpasswd=${pass}. Doesn't require the password is in the file, but again, that's besides the point.
    • rugk
      rugk almost 7 years
      Same question on Security Stackexchange with a detailed answer: environment variable accessibility in Linux
    • dom0
      dom0 almost 7 years
      @DopeGoti: If we're talking automated stuff, not storing the passphrase anywhere in plain text is kinda hard; you'd need a smartcard/HSM and software that can work with that.
    • waltinator
      waltinator almost 3 years
      There's a zero-seperated list of all of a process's environment variables in /proc/$pid/env.
  • Miloš Đakonović
    Miloš Đakonović almost 7 years
    Thanks. I hope "classic UNIX" behavior is dead, at leas on modern distros.
  • user2948306
    user2948306 almost 7 years
    @Miloshio edited to add dates for known versions.
  • Jeff Schaller
    Jeff Schaller over 6 years
    AIX 6100-09 and 7200-00 both prohibit non-root users from seeing other users' environments via ps ewwwax. I don't know when that changed. Additional info: AIX 5.3 went end of support 30 April 2012
  • user2948306
    user2948306 almost 3 years
    @ilkkachu better?
  • Philip Couling
    Philip Couling over 2 years
    Well configured php.ini should never yield everything on an error 500 could just as easily explicitly yield the MySQL password in that scenario as it could every environment variable.
  • Philip Couling
    Philip Couling over 2 years
    I would also add that the security providers I know about require the application to understand how to use them directly. This creates a significant burden on software developers to local equivalent of cloud stack. Eg we've had to slowly remove our calls out to AWS secrets in our code and replace it with docker passing the same secret value in by environment variable. Otherwise developers have to spend ages setting up local AWS simulator to test even small pieces of code.