Ruby on Rails: Danger! Cross Site Request Forgery

by neil on October 1, 2008

Please note this blog has been moved to blog.platform45.com

The attack works by including a link or script in a page that accesses a site to which the user is known to have authenticated. Then a task is performed as the logged in user. 

Huh?

I could create an image tag

 <img src="http://target_site/account/transfer?1milliondollars&from.you.to.me>

or I could put it in a hidden iframe (*holds pinkie up to corner of mouth)

Because you have a valid cookie for the target site this will work. By using post requests for something like this makes it harder to do but still possible. You should be using post when changing the state of a resource anyway. 

What can I do?

From rails 2.0 we have a protect_from_forgery and a secret key. Rails helpers puts this key in every form request. This verifies that the request is coming from somebody using the page. It will protect all POST, PUT, DELETE requests.

If you’re using good ‘ol jQuery you’ll have to set this up yourself.

application_helper.rb

  def yield_authenticity_token
    if protect_against_forgery?
        "<script type='text/javascript'>
        //<![CDATA[
          window._auth_token_name = '#{request_forgery_protection_token}';
          window._auth_token = '#{form_authenticity_token}';
        //]]>
      </script>"
    end
  end

View

 <%= yield_authenticity_token %>

application.js

$(document).ready(function() {
 
	// All non-GET requests will add the authenticity token
  // if not already present in the data packet
  $("body").bind("ajaxSend", function(elm, xhr, s) {
    if (s.type == "GET") return;
    if (s.data && s.data.match(new RegExp("\\b" + window._auth_token_name + "="))) return;
    if (s.data) {
      s.data = s.data + "&";
    } else {
      s.data = "";
      // if there was no data, jQuery didn't set the content-type
      xhr.setRequestHeader("Content-Type", s.contentType);
    }
    s.data = s.data + encodeURIComponent(window._auth_token_name)
                    + "=" + encodeURIComponent(window._auth_token);
  });

Thank you Lawrence Pit for this code.

{ 0 comments… add one now }

Leave a Comment

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">