Hi
I ended up in a discussion about using secure password storage today and
started thinking about solutions for the problem. Some frameworks suggest
putting all kinds of credentials in environment variables. This practice
seems to originate from a recommendation on 12factor.net.
The problem I see with this practice is that it is so easy to leak
environment variables. Like if you are running a phpinfo()
page somewhere
that is not a very big deal until it contains all your passwords and API
keys in plain text. Jikes!
I favor putting credentials in config files that are outside of the
document root. That is also not perfect but at least the risk to leak them
from the environment is mitigated.
Now, I understand that the practice of using environment variables comes in
very handy if you use containers. Just launch your app in a container and
pass it some information about the environment, credentials, ... and you
can reuse the same container in the entire DTAP cycle.
So, how can we improve this situation?
As a PHP FPM user, my solution would be to add a sec_env[] configuration
instruction to the pool configuration that reads the configured value from
the environment, puts it in a more secure location and immediately unsets
it in the environment. Applications will need to read the credentials from
somewhere else, we can provide userland functions for that.
The credentials can be somewhere in the memory of the child process, or
maybe even better is to fork a separate process just to keep the sensitive
variables. The children would be able to communicate with this process over
domain sockets ...
The main intention is to get the credentials out of the environment
variables. You need to setup a connection to a database or API? Get a
password from the secure storage, make the connection and get rid of the
password.
Some side notes:
If it's an environment variable like FRAMEWORK_ENV=prod, which I think is
the valid use-case for environment variables, we don't bother with it.
For CLI applications on the other hand this issue seems less relevant, so I
did not try to solve that problem.
I am aware of tools like Vault, etcd, ... but they solve a different
problem and have their own caveats IMO.
I will be the one writing the proof of concept if this idea would make it
to an RFC. There are still some things I need to figure out but it seems
doable.
I'm looking forward to your feedback.
Kind regards,
Tom Van Looy
ps: today is international password day. What day is better to start a
discussion about secure password storage :-)
2018-05-03 15:29 GMT-03:00 Tom Van Looy tom@ctors.net:
Hi
...
The problem I see with this practice is that it is so easy to leak
environment variables. Like if you are running aphpinfo()
page somewhere
that is not a very big deal until it contains all your passwords and API
keys in plain text. Jikes!
...
The main intention is to get the credentials out of the environment
variables. You need to setup a connection to a database or API? Get a
password from the secure storage, make the connection and get rid of the
password.
Wouldn't it be more feasible to assign the environment variables locally
then clear them from the environment for the rest of the process?
$password = getenv("PASSWORD");
var_dump($password);
putenv("PASSWORD=");
$password = getenv("PASSWORD");
var_dump($password);
phpinfo()
;
The manual of getenv()
does warn that "If PHP is running in a SAPI such
as Fast CGI, this function will always return the value of an
environment variable set by the SAPI, even if putenv()
has been used to
set a local environment variable of the same name." And there's also
apache_getenv() and apache_setenv() to worry about.
But if the point is to avoid accidental leaks, you may want to tackle
the problem from this perspective instead of using a new env mechanism.