We've had discussions about this several times, and haven't come up with something that's satisfactory as a generic replacement, other than "configuration could probably be improved."
> If we ignore them, this means a recently created, pushed and then cloned project is not going to work at all.
Some people replace it with a new file upon deployment, some people use ENV vars, some (most) people never open-source their app, and don't mind employees seeing it...
I absolutely agree that there's no easy solution to this (or it would've been "fixed" already).
> some (most) people never open-source their app, and don't mind employees seeing it...
One of my concerns is that people believe it's only a risk if they ever open source their application. While most apps don't have to worry about a motivated attacker in reality, the risk isn't simply secure or unsecure.
It's more a case of 'more difficult' vs. 'much easier' to compromise. I fear many engineers don't think of securing their apps like this. I know I've only recently begun to understand this way of thinking about security and it's changed the way I code.
Have you considered generating a key at first startup and storing it in a database? Or would that introduce too much unnecessary overhead while introducing an attack vector through the database?
I wish Rails supported two secrets the way Rack::Cookie does by always signing with the first, but accepting either. That way you can rotate the secret without signing everyone out.
I'm surprised that it doesn't? gorilla/sessions[1] does the same; and you can eventually remove your old keys provided you keep your expiry times sane.
Your environment is not secure. The solution for this type of problem (keeping secrets out of source control) is to create a deployment-specific configuration file that is not kept in source control. It can be created out of a generic version that is kept in source control. Then, OS-level permissions are applied so the file is only readable by the processes that need access.
It's worth noting that with 'dotenv' the configuration is stored in a file on the production server before it's loaded into the environment. The security of the method is not based on storing the token in the environment.
The primary advantage I intended was that the secret is confined to one part of the infrastructure (e.g. production server) instead of many (e.g. developer workstations, github, etc).
How is the environment any less secure than memory? If someone can read or mutate your environment, you should assume your app is already compromised and OS-level permissions aren't going to do anything.
I hate code like this that is explicitly aware of the environment. The code says what it will do in an environment, rather than the environment saying what the code should do in it.
I had the same feeling. Inspired by this post, I just moved my secret token config into production.rb, test.rb, and development.rb, and deleted secret_token.rb.
For Python website projects, I enforce the creation of a _secrets.py file in the config folder that is ignored by git and contains all sensitive constants like database information and tokens. Then, in the _base.py settings file (what all other settings files inherit from), I make sure to `from _secrets import *`. I'm not a fan of setting tokens by environment because it gets a little too unwieldy to make sure bash/zsh/whatever sets the variable.
I haven't run into any problems using that method. Does anyone see a reason to prefer environment variables over it?
I wrote a gem called envious that could be used as an alternative to dotenv: https://github.com/RyanNielson/envious from what I can see it does a few things dotenv doesn't. Good guide though, I wrote Envious when I found out this problem existed.
A generic solution to this problem that I don't see mentioned is to have different configuration files for all of ones deployment environements (dev, test, integration....) and have an encrypted config file for production. All the config files go on source control so there are complete records of all changes. Then the key to decrypt the production configuration file is known to the build maintainer and also known by a dedicated build machine (maintained by the build manager).
Doing things this way one can be as secure as one likes while at the same time, builds can be fully automated; builds can be machine independent (if you have a dynamic server environment or ever worry about losing a server), and builds have a complete change history in source control.
Eh... Keeping that in the system environment isn't really any better than hardcoded in a file. There's a long history of "do not trust the system environment" when it comes to security so I can't say I'd recommend this. Last I checked it was also fairly trivial to dump this data out of a running program...
Unless you're grabbing that key out of "secure memory", a HSM or a TPM then its not really particularly secure.
I've found that the figaro gem is also a nice gem to use re: secret tokens and ENV variables in general - esp on Heroku. https://github.com/laserlemon/figaro
I don't understand why a secret token is even necessary. This seems like bad design. As a matter of principle, the server should never trust the client. If authentication is necessary, it should be done on every request. If that is the case, what purpose does the token serve?
The entire principle behind HTTP - what enabled it to conquer and dominate the internet, is its statelessness. Storing and trusting things in cookies is a fundamental security design flaw.
I'm not sure you understand what's going on, which is probably why you've been downvoted. The secret token ensures that the server does not need to trust the client--that's what signing or encrypting session cookies does.
Authentication on every request requires you to store the user's authentication details on the client, which is considerably worse for security purposes than a signed or encrypted session cookie.
[+] [-] steveklabnik|13 years ago|reply
For one example, see this from a year ago: https://github.com/rails/rails/pull/3777#issuecomment-289375...
> If we ignore them, this means a recently created, pushed and then cloned project is not going to work at all.
Some people replace it with a new file upon deployment, some people use ENV vars, some (most) people never open-source their app, and don't mind employees seeing it...
I personally do https://github.com/hotsh/rstat.us/blob/master/config/initial...
Being generic is hard.
[+] [-] danielfone|13 years ago|reply
> some (most) people never open-source their app, and don't mind employees seeing it...
One of my concerns is that people believe it's only a risk if they ever open source their application. While most apps don't have to worry about a motivated attacker in reality, the risk isn't simply secure or unsecure.
It's more a case of 'more difficult' vs. 'much easier' to compromise. I fear many engineers don't think of securing their apps like this. I know I've only recently begun to understand this way of thinking about security and it's changed the way I code.
[+] [-] potomak|13 years ago|reply
[1] https://news.ycombinator.com/item?id=5007530
[2] http://blog.phusion.nl/2013/01/04/securing-the-rails-session...
[+] [-] olalonde|13 years ago|reply
[+] [-] unknown|13 years ago|reply
[deleted]
[+] [-] hayksaakian|13 years ago|reply
To a newbie like me, everything will "just work" in development. In production, I'll get a pretty explicit/precise error message.
[+] [-] willlll|13 years ago|reply
[+] [-] elithrar|13 years ago|reply
[1]: http://www.gorillatoolkit.org/pkg/sessions#NewCookieStore
[+] [-] charliesome|13 years ago|reply
Worse. Knowing the secret token allows an attacker to trivially execute code in your application.
Don't ever let your secret token become public knowledge, and if it does, you need to change it straight away.
[+] [-] olalonde|13 years ago|reply
[+] [-] iguana|13 years ago|reply
[+] [-] danielfone|13 years ago|reply
The primary advantage I intended was that the secret is confined to one part of the infrastructure (e.g. production server) instead of many (e.g. developer workstations, github, etc).
[+] [-] duaneb|13 years ago|reply
[+] [-] manojlds|13 years ago|reply
I hate code like this that is explicitly aware of the environment. The code says what it will do in an environment, rather than the environment saying what the code should do in it.
[+] [-] ryannielson|13 years ago|reply
if ENV['SECRET_TOKEN'].blank? raise 'SECRET_TOKEN environment variable is not set!' end
App::Application.config.secret_token = ENV['SECRET_TOKEN']
[+] [-] michaelrkn|13 years ago|reply
[+] [-] ceol|13 years ago|reply
I haven't run into any problems using that method. Does anyone see a reason to prefer environment variables over it?
[+] [-] grosskur|13 years ago|reply
The envdir program (from daemontools) is useful for setting environment variables in a shell-agnostic way, e.g., run your app with:
See alsohttp://12factor.net/config
[+] [-] ricardobeat|13 years ago|reply
[+] [-] ryannielson|13 years ago|reply
[+] [-] marco_salvatori|13 years ago|reply
[+] [-] bifrost|13 years ago|reply
Unless you're grabbing that key out of "secure memory", a HSM or a TPM then its not really particularly secure.
[+] [-] krapp|13 years ago|reply
[+] [-] unknown|13 years ago|reply
[deleted]
[+] [-] wolframarnold|13 years ago|reply
[+] [-] jsmoov|13 years ago|reply
[+] [-] seniorsassycat|13 years ago|reply
[+] [-] Aqua_Geek|13 years ago|reply
$ SECRET_TOKEN=abcdef SOME_OTHER_VAR=hello rails s
or pollute your .profile with a bunch of app-specific variables.
You don't need it to do it; it just makes it easier.
[+] [-] gridscomputing|13 years ago|reply
[+] [-] SeoxyS|13 years ago|reply
The entire principle behind HTTP - what enabled it to conquer and dominate the internet, is its statelessness. Storing and trusting things in cookies is a fundamental security design flaw.
[+] [-] eropple|13 years ago|reply
Authentication on every request requires you to store the user's authentication details on the client, which is considerably worse for security purposes than a signed or encrypted session cookie.