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* #312 Database config in Ruby - Ruby on Rails - rails), 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