Should the secret_token.rb be added to the .gitignore?

Following the recent Rails vulnerability, should the secret_token.rb be added by default to the .gitignore?

That would break essentially all rails applications that uses a git-based deploy flow, such as Heroku and many other cap recipes.

What might be a good idea though - is to use different secret token for each environment, and allow that to be specified through an ENV variable, like how the ActiveRecord connection parameters current work.

I think it’s quite important that the application secret isn’t shared across applications - and that includes development vs staging vs production environments. I’m not really sure why it isn’t implemented like what I proposed in the first place. Perhaps there are some compatibility requirements that I missed, but I couldn’t think of any off the top of my head.

If people agree that this is worth pursuing, I can put together a PR.

This sits in the same camp as database.yml, adding it to the gitignore inhibits development (the app won’t boot without it) while only introducing security issues for some applications.

We could make some changes for Rails 4 to perhaps store this in a seperate file making it easier to replace, however removing it from git doesn’t really buy us enough to be worth the pain.

That would break essentially all rails applications that uses a git-based deploy flow, such as Heroku and many other cap recipes.

What might be a good idea though - is to use different secret token for each environment, and allow that to be specified through an ENV variable, like how the ActiveRecord connection parameters current work.

There’s nothing stopping you from having it in an ENV var today, that’s one of the benefits of having it set in ruby code rather than

My::Application.config.secret_token = ENV[‘SECRET_TOKEN’]

I think it’s quite important that the application secret isn’t shared across applications - and that includes development vs staging vs production environments. I’m not really sure why it isn’t implemented like what I proposed in the first place. Perhaps there are some compatibility requirements that I missed, but I couldn’t think of any off the top of my head.

If people agree that this is worth pursuing, I can put together a PR.

There’s really no additional risk to the secret being compromised when used in multiple applications / environments than there is when it’s being used for multiple requests (which it is by definition).

Having said that, I think one thing to experiment with is storing the secret in its own file in config. Perhaps config/application_secret.hex. If secret_token isn’t set manually then read and decode it from that file.

If you did that, then people who wanted to could put the application_secret file into their .gitignore and simply store and symlink the file as they do with database.yml.

openssl rand -hex 40 > config/application_secret.hex

Is a lot easier than having to generate a file containing the right constant names and sticking them in the initializers directory.

Following the recent Rails vulnerability, should the secret_token.rb be added by default to the .gitignore?

This sits in the same camp as database.yml, adding it to the gitignore inhibits development (the app won't boot without it) while only introducing security issues for some applications.

Usually I don't use password-based authentication for my PostgreSQL databases but define in pg_hba.conf which hosts are allowed to access it. That way database.yml doesn't need to be made secret. Even though I don't actually use database.yml, mongo.yml, etc, putting all of my configuration in a plain Ruby file since it makes it much easier to me to manage the many environments our application runs on and makes it much easier to set up a new environment as I only have to edit a single file to change any settings (including those usually available at config/environments/env_name.rb).

We could make some changes for Rails 4 to perhaps store this in a seperate file making it easier to replace, however removing it from git doesn't really buy us enough to be worth the pain.

With regards to the secret_token, anyone concerned about it going to the source repository should consider storing it on the database itself. That way you wouldn't have to worry about it if you can make sure no one will have free access to your database...

Best, Rodrigo.

I’ve talked at length with developers in Heroku, we’re interested in making the default security of new Rails apps better out of the box.

I know there is a much larger discussion going on and I believe there are one or more people actively looking into the options. I would like to work with anyone interested in security to figure out a good workflow with Heroku. One option we discussed would be automatically setting the a config var such as SECRET_TOKEN from the Heroku buildpack, so that it didn’t matter if your source got exposed, they would need to get into your app as well.

Being able to set the token from an environment variable could also allow services to rotate the token without having to modify any files, or touch anything you’ve got in Git. Just a thought.

So again: feel free to ping me on twitter @schneems or in chat: richard.schneeman@gmail.com if you’re working on security updates. I would like to help make the default experience secure and seamless.

just looked in the application which I just workinig on and indeed I missed this securty_token.rb thingy though I know about it. PLEASE just make the overall setup more secure.

for example development + test could use a SecureRandom.hex(64) as security token and production needs to do something manually (or so).

just keep things secure by default.

that are my 2 cents.

- Christian

Richard,

That’s overall the way I would go too, with two changes.

  1. Name the environment variable RAILS_SECRET_TOKEN - i.e., prefixed with RAILS_ - since an application may have many secret tokens unrelated to session cookies. Environment variables related to a given library or framework ought to be prefixed with the name of that library or framework, such as RAILS_RELATIVE_URL_ROOT, to avoid easily-avoidable conflicts and incompatibilities.

  2. To support token rotation, there needs to be support for two tokens at once: the current token and an old token. The old token, if it exists, would be used to read session cookies in the HTTP request after the attempt to read them with the current token fails, but the current token would always be used to sign all session cookies in every HTTP response.

Cheers,

Jay

@schneems. @jay. Good ideas.

A fear that I have is that these conventions are Heroku specific, and not deployment agnostic. This feels enterprisely or Microsoft-ishy (or this feeling could be my own emotional baggage).

To make this a Rails deployment convention and not just a Heroku, maybe make a capistrano equivalent to set the secret_token from a shell set variable?

Thoughts?

It's only Heroku-specific in the sense that Heroku basically follows http://www.12factor.net/ :wink:

Weston,

I see using environment variables as the interface to configure your application as the anti-Microsoft. As the Unix. It is simple to implement in both the infrastructure (if you are implementing your own) and in your application.

The convention is not not Heroku-specific; it is specific to any application which follows the convention of being configured via environment variables, including Heroku applications, 12factor-style applications, CloudFoundry-compatible applications, etc., and any application willing to add two lines of code and a line of whitespace (see below).

I’m not sure what’s available for Capistrano, but anything that could set up environment variables in a YAML file and symlink the YAML file into the application, so that the application could read it on boot, would be good.

Rails could even help this along, by natively supporting reading a config/environment.yml file with environment variables. The file would be gitignored by default and Capistrano could symlink in a production config/environment.yml file when deploying. But it’s easy to extend your own application to try to read config/environment.yml early in the boot phase on your own.

require gems w/ bundler

import environment variables

environment_yml = File.expand_path(“…/environment.yml”, FILE)

ENV.update(YAML.load_file(environment_yml)) if File.exist?(environment_yml)

setup app config based on environment variables as necessary

module MyApp

class Application < Rails::Application

config.something = compute_something_from(ENV)

end

end

Rails supporting a RAILS_SECRET_TOKEN environment variable natively in the generated secret_token.rb (or some other way, as well as a corresponding environment variable for the old token so that you can do zero-downtime, zero-session-clearing, key-rotation) may help the situation with secret-tokens in public repos going forward. Two lines of code, a symlinked YAML file with Capistrano or a config var on Heroku, and it’s done.

Cheers,

Jay

Looks like can set ENV variables from Capistrano fairly trivially:

http://craiccomputing.blogspot.com/2009/08/capistrano-and-environment-variables.html

API docs for Capistrano config:

http://rubydoc.info/github/capistrano/capistrano/master/Capistrano/Configuration/Actions/Invocation

Hi Jay,

I had the same idea last week to “gracefully” switch sessions by setting a 2nd secret_token. I saw your post over the weekend so decided to put my extension into a gem. You can grab the gem here, and whenever you need to use it:

Gemfile

gem ‘secret_token_migration’’

config/initializers/secret_token.rb

SecretTokenMigrationApp::Application.config.secret_token = NEW_TOKEN

SecretTokenMigrationApp::Application.config.deprecated_secret_token = OLD_TOKEN

And then just remove that when you feel comfortable that your most active users have been transitioned. There’s also a built-in ActiveSupport::Notification so you can graph the amount of users getting transitioned.

Tests pass and this works for me in a development environment, but I haven’t used it in production yet, so I’d love to hear any feedback on it.

-tieg

PS I just want to emphasize that this isn’t for a compromised secret_token, just for maintenance reasons.

Another option would be to add support for Procfile and/or .env files, either via Foreman, or integrating function similar to the dotenv gem (GitHub - bkeepers/dotenv: A Ruby gem to load environment variables from `.env`.). The .env files offer a simple way to handle environment variables, and the Procfile simplifes developing applications that use queues and other background services. It also eases deployment, not just to heroku but also other systems, via the forman export command.

Yeah, it would be awesome to see that out-of-the-box in Rails.