Web Application Security Checklist

Cross-site Scripting (XSS)

Is all user input sanitized before entering the database? Are user-defined values escaped on output? Also, watch out for reflected XSS where a user parameter is directly output in the view (even if it never gets stored anywhere -- for example, a search term).

SQL Injection

Is all user input sanitized before entering the database?

NOTE: We get this for free in Rails, just make sure you're using ActiveRecord's DSL and not directly interpolating anything in traditional Ruby fashion. Example:

GOOD

User.find(:all, :conditions => ["name = ?", params[:name]])

BAD

User.find(:all, :conditions => ["name = #{params[:name]}")

Parameter Injection

Mass assignment or attribute values is something used extensively in Rails code for form targets; however, we need to be cautious here as a clever hacker can easily inject parameters into a request. For example, we may expect the following request:

POST http://site.com/users user[name]=Brian&user[email]=brian@site.com

And our controller could be setup the following way:

def create
  @user = User.create(params[:user])
  ...

A malevolent user can add any other parameters he/she wants to the request and our User.create code will call <param>= for each of those parameters. This means a user can easily change foreign keys, etc -- in fact, they can call any method that ends in an equals sign and takes one argument. Fortunately, Rails gives us a very simple mechanism for protecting these values: you can use attr_protected or attr_accessible in your models to disallow mass-assignment for particular attributes. Personally, I recommend always using attr_accessible over attr_protected since it follows the principle of implicitly disallowing everything that isn't explicitly allowed.

Cross-site Request Forgery (CSRF)

Use a token to ensure that all forms (and any non-GET requests) are coming from the site rather than an external request. Rails 2+ gives you this functionality by default.

HTTPS/SSL

Not much to say here. Use SSL! With the power of processors ever-increasing and the cost ever-decreasing, there's not much of an excuse for not using SSL everywhere on your site. After all, scaling at the load balancer level really isn't that hard anyway.

Cookies

Use http-only on your cookies everywhere possible. If a user finds an XSS hole on the site, it gives you one more layer of protection against session hijacking. Also, for authenticated sessions, you probably want to set the secure flag on your cookies to prevent the session_id from being passed around in clear-text.

Authenticated Sessions / Login

A few easy things to mitigate session hijacking:

Logging

Ensure that sensitive data is filtered out before being logged. This includes credit card info, passwords, etc.

Data Enumeration

Is there an easy way for a user to determine whether a particular username exists in the system? Any other sensitive data that would be easy to enumerate. Naturally, this only matters in certain situations, so there are no hard and fast rules here. Sample targets include: