Reputation: 4516
I've read a pile of other related questions... nothing really seems to answer the question I have.
My application will integrate with several different third party sites. (ebay, paypal, google, amazon...) It is a product management system and it pushes products all over the place...
Of course since it interacts with all these sites, it needs usernames, passwords, tokens.. ect.. Now I don't think it's really a good idea to store these things raw, but I still need to be able to get them raw, so I can embed them in the XML I send, or the HTTP header.
Does anyone have a suggestion on how to store the info? Is there a rails GEM?
Upvotes: 1
Views: 1200
Reputation: 8106
Storing in server environment variables is the best practice for storing credentials to the DB, third-party credentials, etc. according to Twelve-Factor App methodology. How to store them depends on what you are using and how you have it setup. This promotes keeping creds out of source control, out of the database, and local to the server environment. To access an environment variable, you can use ENV
, e.g.:
ENV['something']
Concerns about limitations and security:
For those storing thousands or more passwords/credentials in env vars, here are some things to help you decide whether or not to use them, in terms of feasibility and security:
If the OS user that is running the web application or service has read-only access to the Rails application root directory and subdirectories only and therefore has read access to a well-known (relative or absolute) path of a credentials/secrets file, and a developer accidentally writes a service that uses a request param as part of the pathname to a file read into a variable returned to the client, then a user of the application could potentially remotely dump all of your creds. If you put those creds into a place much less accessible by the OS user running the application in a pathname which is not easily guessable, you will reduce the risk of that exploit being used successfully to dump those creds.
You should also do what you can to make it harder to use those credentials outside of the server environment. This way, if they dumped all the credentials via an app/service exploit but cannot use those credentials outside of that environment, then they would have much less value.
The limit of how much can be stored in env variables is likely higher than you might suppose. For example, in macOS with RVM loaded which wastes a ton of environment space with bash functions, etc., I was able to get 4278 53 char length creds (e.g. bcrypt-ed):
test.sh
#!/bin/bash
set -ev
for i in `seq 1 4278`;
do
export CRED$i='...........................................'
done
ruby -e 'puts "#{ENV.size} env vars in Ruby. First cred=#{ENV["CRED1"]}"'
output:
$ time ./test.sh
for i in `seq 1 4278`;
do
export CRED$i='...........................................'
done
seq 1 4278
ruby -e 'puts "#{ENV.size} env vars in Ruby. First cred=#{ENV["CRED1"]}"'
4319 env vars in Ruby. First cred=...........................................
real 0m0.342s
user 0m0.297s
sys 0m0.019s
When I exceeded that, I got ruby: Argument list too long
.
If you were to have a service in your app that could spit out any environment variable value, then you'd obviously NOT want to store creds in env vars as it would be less secure, but in my experience I've never encountered a development situation where ENV was exposed intentionally except for something like a Java administrative console that might spit out all system properties and env vars.
If you store creds in the DB, you're at more of a risk since SQL injection exploits are typically much more common. This is one reason usually only hashes of passwords are stored in the DB and not encrypted creds to other services.
If an attacker logs into the server itself and has access to the environment of the user running the web app/service or can find and read files containing the creds, you are out of luck.
Upvotes: 1