Saturday, October 22, 2011

Rails Security Refactor: Protect Those Attributes!

Rails in the enterprise is still a fairly new concept, but the same web development principles we have also exist in this new realm. One no-brainer is security, and one no-brainer part of security is protecting data from malicious user input.

The basic Rails ways to protect attributes on a model are attr_protected and attr_accessible. If neither are set, it's easy to imagine a situation where a user updates his attributes and the corresponding model has a boolean admin field on it. The user can trivially submit post data that looks like this:
params: { "user" => { :email => "foo@bar.com", :first_name => "Joe", :last_name => "Hacker", :admin => "true" } }
Oops! Now Mr. Hacker is Mr. Admin!

So how do we get from here to (more) secure? Throwing attr_accessible on the model to whitelist is the safest, but it can cause a lot of unknown breakage if there aren't tests around the fields, which there probably aren't because why would someone test the fields for accessibility if they are automatically accessible? An interim step is to create a blacklist using attr_protected to only protect specified fields, get tests around these protected fields, and then upgrade to attr_accessible.

For our user model, let's protect that admin field:
Class User < ActiveRecord::Base
  attr_protected :admin
end
And the tests:
describe User do
  describe "with protected fields" do
    context "including admin" do
      let(:user) { Factory.build(:user, :admin => false) }

      it "cannot mass-update" do
        user.update_attributes({ :admin => true })
        user.admin.should be_false
      end
    end
  end  
end
We instantiate a user object with admin set to false, try to update that field, and ensure that it did not get updated. If we use user.update_attribute(:admin, true), the test would fail because that skips all the ActiveRecord protection, so we use user.update_attributes(). Doing this for all the fields we want to protect will eventually get us to the point where we can swap out attr_protected with the easier-to-deal-with attr_accessible. Since we need to be explicit with attr_protected, it can get to be difficult to maintain quickly since we need to remember to add each new field we want to protect to the list and test it.
Class User < ActiveRecord::Base
  # attr_protected :id, :admin, :awesomeness_rating, :money
  attr_accessible :email, :first_name, :last_name
end
That's better. Tests and iterative development to the rescue!

Friday, October 7, 2011

Our Interview Process

Our Hiring Process

At Crowdcast, we're currently hiring developers, and through much practice we have come up with an interview process that maximizes our chances of finding a candidate who will be a good fit.

There are a few steps that aren't always in the same order, and we may even skip some depending on the candidate.

The Phone Screen

I'm not involved in this first step. The engineering manager will talk to a candidate initially to find out if there are any immediate red flags and to clarify his experience. If nothing strange happens (believe me, there have been strange happenings), we'll schedule the candidate to come in or give him a preliminary coding test.

The Rails Test

We send the client a small Rails coding project that should only take a few hours. We'd like him to create a Rails application with some basic functionality and minimal markup and styling (design is a bonus but not a requirement), put the project on his Github account, and send us a url to the code. This is a Fizzbuzz-style question for the Rails framework, and it also implies that he has a Github account. You do have one, right? If the candidate can already show us Rails code, we may skip this step and just bring him in to the office.

The Onsite Interview

We then bring the candidate in for a few interview rounds. I'll ask a candidate about previous experience and what he enjoys working on to establish a little history and familiarity and to decode what's written on his resume. I'll next go through a technical screening about Ruby, some basic questions and some slightly-less basic questions, and I'll let the candidate explain as much or little as he'd like. A good one will definitely have a lot of say for some of the answers, and a short reply is usually an indication of minimal experience with the subject matter.

Next, we'll get into some Rails-specific questions, both methods and techniques. It's certainly not necessary to know everything about the framework, especially given its development speed, but there are some core ideas that get used often that he should be familiar with. If the candidate can teach me something, that makes me very happy.

The Pair Programming Exercise Part I

A new wrinkle we've introduced. Since I'll be pair programming with someone, I'd like to know how he thinks and how we'll work together. We'll sit at one computer and, with the candidate driving, work through a small Ruby problem. We'll do TDD (we use Rspec but that's not a requirement). The problem should take 20 - 40 minutes and leaves a lot of room to delve into interesting design issues and refactorings. This is the fun part.

The Pair Programming Exercise Part II

The last step is to invite the candidate back to pair program on real code for a few hours. We need to make sure we're a fit for each other, and this gives him an opportunity to engage our code base and be part of the team. This is not just for me but for everyone in the office, and of course the candidate, to assess the interactions.

Post Mortem

Does any interview process find the perfect candidate? Not that I've discovered. We can't go as in-depth as Hashrocket, but we can get partially there with the multiple pairing exercises and full team interaction. It's so incredibly important to get along with coworkers since we spend as much time at work as sleeping (actually, it's probably more time at work), so just having the technical chops is not enough. We hope that our process gives us the knowledge to make the right decisions for everyone involved.