Idempotent Seeds

You Reap What You Sow rake db:seed


When working with database based applications more often than not, some seed data needs to be created. For example, I’ve used seed data to create an admin_user and a few dummy_users so the site can be used upon a fresh install. Some other common cases include things like, list of names of countries/states, list of user roles, list of permissions etc.
This post is about some ideas to manage seed data in a Ruby on Rails project.

In a Rails application seeds can be put at two places

  • db/seeds.rb [Standard practice]
  • db/migrate/232422_some_migration.rb [*its a possibility]

db/seeds.rb is the obvious place for seeds. Don’t mess around with it unless absolutely necessary.

Some points to keep in mind when sowing seeds:

  • Handling large seed data
    • Split seed files into multiple files clearly indicating your objects and business logic. A sample might look like
    •  Inside seeds.rb require sub seed-files as
      require 'seeds/user.rb'
      require 'seeds/roles.rb'
      require 'seeds/plans.rb'
    • If number of seeds for a business object is large, consider loading it from yaml files. Keeping business logic separate from data is a good practice.
  • Idempotent seeds
    • Idempotent,  a mathematical term that means that something remains the same when some operation is applied to it, using itself as input.
    • For example, multiplication by identity element  5 X 1 = 5.
    • Having idempotent seed files means, they can be run multiple times without causing any issue.
    • Instead of creating or updating objects blindly, it first tries to find the object and check its state.

CSRF and RAILS protect_from_forgery

Cross-site request forgery, also known as a one-click attack or session riding and abbreviated as CSRF or XSRF, is a type of malicious exploit of a website whereby unauthorized commands are transmitted from a user that the website trusts. Unlike Cross Site Scripting (XSS), which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user’s browser.Lets take a look at the schematic of the CSRF

CSRF Scheme
  • Step1: The Victim connect to secure Bank websites and logs into his account.
  • Step2: A cookie set in the Victims browser containing the session id of the victim.
  • Step3: Victim trips into visiting a malacious page.
    Step4: Victim recieves a html page containig malacious hidden form.
  • Step5: A web request is executed from the victims browser carrying the context of cookie set in Step2.
  • Step6: Bank Server completes the web requests.

Conclusion: Banking server failed to verify the validity of the web request and hence executed it without the victims knowledge.

Now we know what CSRF is, lets see how Rails help prevent CSRF.
As Rails uses MVC architecture, Controller actions are protected from Cross-Site Request Forgery (CSRF) attacks by including a token in the rendered html for your application. This token is stored as a random string in the session, to which an attacker does not have access. When a request reaches your application, Rails verifies the received token with the token in the session. Only HTML and JavaScript requests are checked, so this will not protect your XML API (presumably you’ll have a different authentication scheme there anyway). Also, GET requests are not protected as these should be idempotent. The requests are validated using the following peice of code

This can be enabled with the protect_from_forgery method, which will perform the check and handle unverified requests, if the token doesn’t match. And it will add a _authenticity_token parameter to all forms that are automatically generated by Rails. It is recommended that this method is added in your ApplicationController, and later on you can skip it in other controllers if not required.

With all this in mind lets take a look at Rails source code.

From the code, we figure out, CSRF protection resets session and lets the request through when CSRF token verification fails.
This in itself is a CSRF vulnerability since it allows anyone to logout users by directing their browser to a page that requires CSRF protection

With Rails 4 application, the ApplicationController now passes a parameter to protect_from_forgery.

This raises an exception when an unverified request is encountered. Same behavior can be achieved with Rails 3 by overriding the default handle_unverified_request method.