If you are anything like me, you can easily hack your way through things and get them to work, but are always afraid that you are missing something. Well, I’ve come up with my own list of best practices before I deploy a Rails application to the public.
Some of these best practices are, of course, universal to any web application development effort, so I won’t go deep into them – but at least they are here for “the record.”
- Do NOT store user passwords as clear text.
- NEVER allow user submitted information fall directly into database queries.
- Always backup code, data AND user uploaded data such as images, documents, etc.
- Validate the content type and extension of user submitted files and make sure the upload directory is secured from running scripts.
Now onto the Rails specific practices. Some of these may be repeats from other lists that you may have encountered, but becoming a Rails developer I found that they were key to ensuring that my applications stayed secure and performed as designed.
Check your users
What I mean by this is ensure that the logged in user has the ability to perform the requested action. Sure with the :before_filter on a controller, we’ve all come across the authenticate method. But also check against what action that user is trying to request for that controller. You may have roles in your application where admins can delete users but users can’t. If you are just checking to see if a user is logged in, then you will have your plain ol’ registered logged in users deleting everyone. That’s no good.
create methods such as
. You could even use a gem like Ryan Bates’ Cancan which is nice and simple to implement.
Cross-Site Request Forgery or better known to most as CSRF
This is one of the nice security features that lured me to Rails. In PHP and other web languages, this was something you had always take into account and make sure, at the most basic level, that you wrote a method to cleanse and validate the session token with each form submission.
In Rails, make sure you enable protect_from_forgery instance method in your controllers. Also (what I enjoy the most), use form helpers to ensure that your authenticity token is on all form submissions. The reason I like it so much is in using the form helpers I was just coding the form, but with the magic behind the scenes, it was adding the tags necessary to carry out the security. To make this magic work, include csrf_meta_tag (or in Rails 3, csrf_meta_tags) in your HTML head tag.
Watch for prying eyes
Make sure you filter out sensitive information from your logs. I’ve developed many applications with sensitive information being flowed back and forth across the wire, such as online credit card transactions, healthcare patient information, etc. If, and when, there’s an issue and someone else needs to take a look into the logs to find the error or a trace of what’s happening, make sure that sensitive information, such as credit card information, patient records, passwords, etc are removed from the log files. 9999 out of 10000 times, that information isn’t the cause of the issue and no sense in possibly risking that data getting out.
In your config/environments/production.rb file, you can use config.filter_parameters to set which pieces of information you want to have removed from the logs, just by adding in the symbols separate by commas. i.e.
config.filter_parameters = [:ccexpdate, :ccnumber]
Make sure your assignments are covered
Issues can easily arise from overwriting a user’s account id. Or maybe your application does not allow the user to change their username once it’s set. Whatever the case may be, you want to make sure that these sort of things don’t happen inside a profile update.
Rails makes it nice and easy with the :attr_accessible method inside your model. This disables the mass assignment on all attributes of a model to that of the attribute that is listed. You could also use :attr_readonly as well, which only allows the attribute to be set on the create action.
Finally, clean up after yourself
Everyone, especially sys admins, hate messy people. Think about the space being taken up by your application. Then think about how many times you’ve released it. Uh oh, “can you even see the floor in your room” as my Mom used to say. Each time you release your application to production (if set up properly), you’ve marked the codebase for release and more than likely moved the symlink of your application’s root directory from one directory to another. Leaving behind a rollback release in case of some disaster where you code blows up.
Do you need the rollback from 19 releases ago, I’m thinking that you don’t. Most people don’t even need past 3. But for my own sanity, I like to keep 5. I use Capistrano for my deployments and there’s a nice and easy way to keep you and your sys admin going to lunch.
set :keep_releases, 5
in your deployment recipe. By putting this into your recipe, it stops you from having to go into the filesystem and removing all the directories, 5 back from the current one, manually. It performs this task once your deployment is completed successfully.
Sure there’s a lot more checks to be had, I know I left a few off this list, but I think that these are the bare minimum to launching your Rails app into a production environment successfully.