Cookie session security and open-source

I've noticed that quite a number of open-source Rails apps are using
the new cookie session feature, and have the session secret predefined
in the config/environment.rb file. I'm no expert on this, but I was
under the impression that the "secret key" needed to be kept secret or
there is a security problem. Maybe everyone who downloads these apps
is taking the time to change the secret key before deploying them into
production, but I generally haven't found anything in the installation
instructions to indicate that end-users should do so. This concerns me
a bit.

Clearly, there's an easy solution to this (potential) problem: don't
use a secret key that you didn't generate yourself. What I'm wondering
is if this is an area where Rails could be doing more to automate this
stuff. Perhaps a solution would be to store an automatically generated
session id and key in the database, much like with schema_migrations?

Thanks,
- Trevor

When you run `rails myapp` it creates a new key for you, so every app
should be different. Checkout the generator file at:

http://github.com/rails/rails/tree/master/railties/lib/rails_generator/generators/applications/app/app_generator.rb

Right, but lots of open-source applications come with an config/
environment.rb file with that secret key already created. Maybe I'm
worrying over nothing, but it seems to me that people could be
checking out open-source apps and running them in production with the
secret key that was checked into the open-source project's repo, if
that makes sense.

- Trevor

I've noticed that quite a number of open-source Rails apps are using
the new cookie session feature, and have the session secret predefined
in the config/environment.rb file. I'm no expert on this, but I was
under the impression that the "secret key" needed to be kept secret or
there is a security problem. Maybe everyone who downloads these apps
is taking the time to change the secret key before deploying them into
production, but I generally haven't found anything in the installation
instructions to indicate that end-users should do so. This concerns me
a bit.

Clearly, there's an easy solution to this (potential) problem: don't
use a secret key that you didn't generate yourself. What I'm wondering
is if this is an area where Rails could be doing more to automate this
stuff. Perhaps a solution would be to store an automatically generated
session id and key in the database, much like with schema_migrations?

Yep, that's an exploit waiting to happen.

Another option. I was thinking of putting the secret key in a separate
file and not checking it into source control. Have
config/environment.rb load that file, or create it if necessary. So
if you're just checking out the sources, you get a different key from
everyone else. For deployment, symlink to a share directory, say
somewhere in /etc.

Assaf

I've noticed that quite a number of open-source Rails apps are using
the new cookie session feature, and have the session secret predefined
in the config/environment.rb file. I'm no expert on this, but I was
under the impression that the "secret key" needed to be kept secret or
there is a security problem. Maybe everyone who downloads these apps
is taking the time to change the secret key before deploying them into
production, but I generally haven't found anything in the installation
instructions to indicate that end-users should do so. This concerns me
a bit.

Clearly, there's an easy solution to this (potential) problem: don't
use a secret key that you didn't generate yourself. What I'm wondering
is if this is an area where Rails could be doing more to automate this
stuff. Perhaps a solution would be to store an automatically generated
session id and key in the database, much like with schema_migrations?

I think the correct fix here is to notify the projects concerned and
tell them what they need to do. Assaf's suggestion of reading from a
file is probably the best bet for them.

I'm assuming these projects don't ship with a database.yml file
including a password, this is basically the same thing.

Yes, agreed. But maybe it would be a good idea to store the secret key
in an external file. If the key file doesn't exist, then a new key
file is generated. The developer can then choose whether or not to
include the key in the repository. This would save open source app
developers a little bit of hassle.

I can only imagine one thing going wrong: people deploying the app
over multiple web servers while forgetting to copy the key file too.
If this happens then each web server will have a different secret key,
and this will break a user's session if he's load balanced to a
different web server.

Thanks for pointing this out Trevor. As for a solution, I agree the
key should be in an external file instead of included directly into
the environment.rb. This could be auto-generated when the Rails app is
first made, but not after that. This way it avoids the potential
problem Hongli mentioned of unintentionally generating the file on a
distributed server setup. There could be a rake task to trigger the
regeneration of the file for convenience.

Perhaps this file could be more generic as well, kind of a designated
place to put all secret keys/passwords.

Ryan

Thanks for pointing this out Trevor. As for a solution, I agree the
key should be in an external file instead of included directly into
the environment.rb. This could be auto-generated when the Rails app is
first made, but not after that. This way it avoids the potential
problem Hongli mentioned of unintentionally generating the file on a
distributed server setup. There could be a rake task to trigger the
regeneration of the file for convenience.

We use a task called setup. Once you get the source code, there are
still a few things you need to do before you're up and running:
installing gems, creating dev/test database, populating dev database,
etc. So the first step is running rake setup, and that could take
care of generating a secret key for you. The rest will be taken care
of by .gitignore.

Perhaps this file could be more generic as well, kind of a designated
place to put all secret keys/passwords.

I hope so, that way we can have generic tasks that work across apps.
One I'm thinking of is setting a secret key on the server and linking
to it during deployment. You probably don't want to use the same key
in development and production. I only need to distract you for a
minute, peek at your machine to find out your site's secret. So this
applies also to closed-source apps.

Assaf

Thanks for pointing this out Trevor. As for a solution, I agree the
key should be in an external file instead of included directly into
the environment.rb. This could be auto-generated when the Rails app is
first made, but not after that. This way it avoids the potential
problem Hongli mentioned of unintentionally generating the file on a
distributed server setup. There could be a rake task to trigger the
regeneration of the file for convenience.

Perhaps this file could be more generic as well, kind of a designated
place to put all secret keys/passwords.

If we generate the file when we create the application, people are
going to add it to source control just like they do environment.rb. I
really don't think we need to change what rails does here, the
applications simply need to have:

:secret=>File.read(File.join(RAILS_ROOT, "config", "secret.txt"))

If we generate the file when we create the application, people are
going to add it to source control just like they do environment.rb.

Most don't add database.yml to source control (as it should be), so I
think it's possible to train them to not add another file.

I look at it as a separation of concerns. You wouldn't put your
database password or any other password in environment.rb, right? To
me this seems just as important. Whether it's a closed or open source
app, it makes sense to move anything secret out of source control. And
for most that means out of environment.rb

I really don't think we need to change what rails does here, the
applications simply need to have:

:secret=>File.read(File.join(RAILS_ROOT, "config", "secret.txt"))

Right, it's not too hard to move this into an external file, so this
probably isn't that big of a deal. I just think security should be the
convention instead of requiring extra steps.

Regards,

Ryan

I'll reach out to the open-source projects that I know to have this
issue. This should go a long way toward prevent this from becoming a
real-life problem. Of course, the people who have installed an
application with a publicly available secret key would need to change
their key for real security (which would invalidate all of their user
sessions).

While this issue is something that can be approached by educating
people on the security risks, I feel that Rails could better promote a
best practice in this regard. In my brief investigation, I found that
the majority of open-source Rails apps are potentially vulnerable in
this way.

Here's a quick list of some ideas on how to approach this in order of
probable impact:

1) Inform developers and users of open-source projects of this
potential issue
2) Education people on the best practices in this area via blog posts
and whatnot
3) Further stress the importance of keeping this key secret in the
environment.rb comment text
4) Automatically generate the secret key on app generate, store it in
a separate file, and note that it should be kept secret
5) Generate a secret key automagically and store it in the database to
avoid having the extra file to ignore
6) Provide a new config/config.rb file or similar (and perhaps
encourage people to use this for api keys, db passwords, etc)

Of course, some of these ideas may not appeal to everyone (*cough*
http://rails.lighthouseapp.com/projects/8994/tickets/312-database-config-in-ruby),
and I'm not sure what the best approach might be. I'm not an expert
with this stuff. I just hope to help others avoid any problems that
could potentially arise because of this.

Thanks again for your replies,
- Trevor

If you're looking for open source apps to warn, a good place to start
is http://www.opensourcerails.com/.

I like the idea of adding a comment in environment.rb about this issue
(if it's not going to be in an external file by default).

BTW, just a note to developers. If you're changing the session secret,
it's best to change the session key at the same time. This way they
don't get a 500 error the first time they visit with the old session.

Regards,

Ryan

I'm in the process of sending out notes to the open-source app
developers on Open Source Rails right now. Here's a link to a quick
blog post I did that shows a workaround for this issue. I'm not in
love with the technique, and it causes a small hiccup with Heroku
deployment because of the way they automatically create and configure
databases. In any case, it's a good start:

http://almosteffortless.com/2007/12/27/configuring-cookie-based-sessions-in-rails-20/

Thanks all,
- Trevor