Advanced Rails - Building Industrial-Strength Web Apps in Record Time

(Tuis.) #1

134 | Chapter 5: Security


It is perfectly OK to validate data at the client. This is useful because when users
make mistakes filling out a form, client-side validation saves a round-trip to the
server. But if the only thing keeping invalid data out of your application is a piece of
JavaScript, malicious users can simply turn off JavaScript and submit your form.


These two methods of validation represent two different perspectives. Client-side
validation (if any) should emphasize usability, while server-side validation should be
driven by security.


Cookies


In Rails, there is usually no need to deal with raw cookies. The session abstraction
provides a way to store data in a way that looks like a cookie but can be trusted. The
session store is usually a server-side data store tied to a unique session identifier in a
cookie. Because session IDs are sparse and hard to guess, it is a safe assumption that
if a user presents a particular session ID, he has access to that session. And since the
application code is the only thing that can access the session store, you can trust that
the data you read is the same as what you wrote.


There is a new method of session storage, CookieStore, that is now the default in
edge Rails and Rails 2.0. It marshals the entire session into a cookie, rather than key-
ing a server-side session from a client-side cookie. The idea is that most sessions are
small, usually containing only a user ID and flash message. Cookies work fine for
this (they usually have a 4 KB limit). Rails ensures data integrity by signing the
cookie with a message authentication code (MAC) and raising aTamperedWithCookie
exception if the data was modified.


Double-check everything


Here is another mistake that is easy to make in Rails. Because the REST philosophy
behind Rails encourages resource-based URIs (each URI represents a particular
resource or object), it can be easy to overlook security. This happens often when
finding a record from the database by primary key—often it is easy to neglect check-
ing for proper ownership. Here is an example that illustrates that problem:


app/models/message.rb
class Message < ActiveRecord::Base
belongs_to :user
end


app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def show
@message = Message.find params[:id]
end
end


That example would allow anyone to read any message, even messages owned by
other users. In this case, you probably want to restrict viewing of messages to the
users that own them. The proper way to do that is:

Free download pdf