Sunday, December 13, 2009

Signature verification does NOT work with Facebooker and Rails 2.3

I've been working on a Facebook application called My Trips (http://apps.facebook.com/my_trips/) for several months now in my free time. I am using the Facebooker gem for this project. If you are interesting in developing Facebook applications with Rails, I would highly recommend reading Developing Facebook Platform Applications With Rails, about developing Facebook applications with Facebooker.

At some point I'm going to do a comprehensive write up of my experiences developing a Facebook application with Rails and Facebooker. But until then, I figured I should share one important thing I found.

Facebook passes signatures to your application on every request. The checksum of all signature parameters, plus your "secret key" (a key assigned to your application when it's installed, and never sent in HTTP requests) must equal the signature parameter sent to you by Facebook in params. This ensures that the request actually came from Facebook and not from a third party spoofing Facebook. This is a great security feature. Facebooker automatically checks the signature on every request from Facebook, and throws an exception if the signature doesn't match before your controller code is hit. At least that's how it works with Rails 2.2 and earlier.

With Rails 2.3, Facebooker adds the Rack::Facebook rack extension that is supposed to do this signature verification one level above Facebooker, among other things. However, Rack::Facebook didn't actually verify signatures in my application. I made requests by spoofing Facebook, and just manually typing in URLs without even attempting to spoof, and my requests were processed. They should not have been.

I couldn't really figure out why Rack::Facebook wasn't doing this. Since the signature verification code is in Facebooker and works in Rails 2.2 and earlier, I decided to modify the Facebooker code to do this check explicitly. To do this, edit the facebooker/lib/facebooker/rails/controller.rb file, find the verify_signature method, and comment out the first 3 lines that does a check to see if Rack::Facebook is loaded. When you restart your application, Facebooker goes back to verifying the signature itself. After doing this, my spoofed and manual requests were correctly caught.