Jester and Rails's forgery protection

12 views
Skip to first unread message

Nat Budin

unread,
Aug 21, 2008, 2:41:18 PM8/21/08
to jest...@googlegroups.com
Hello everyone!

As of Rails 2.0, there is an optional (but turned on by default in new
apps) mechanism for doing cross-site request forgery (CSRF)
protection. This article provides a decent overview of how it works:
http://baseunderattack.com/2008/04/18/ruby-on-rails-and-csrf-protection/

Unfortunately this seems to cause some problems for Jester when turned
on. Non-GET requests to the server will fail without the correct
authenticity_token parameter being passed in, and Jester has no way of
automatically inserting them.

To make matters worse, there doesn't seem to be any way of manually
passing in additional URL parameters on calls such as obj.save,
obj.delete, and Class.create. Adding the authenticity token into the
URL itself when creating the Jester resource class won't work, because
(if I understand correctly) every GET request generates a separate
authenticity token for POST/PUT/DELETE replies.

It seems to me like the only solution is to add some way of passing in
additional URL parameters just for this request. In other words:

bob = Person.find(5)
bob.name = "Jack"
bob.save(callback, {'authenticity_token': '23489fe013931101'});

But I'm not a huge fan of this option, because it seems not
particularly clean from an API point of view.

Jester maintainers, do you have an opinion about what might be the
best way to accomplish this?

Nat

Chad Pytel

unread,
Aug 21, 2008, 2:46:10 PM8/21/08
to jest...@googlegroups.com, jest...@googlegroups.com
As with normal Active Resource, it's expected that you disable forgery
protection for resources that will be accessed.

Nat Budin

unread,
Aug 21, 2008, 2:59:45 PM8/21/08
to jest...@googlegroups.com
That would certainly work, but it seems like a bad idea to just
disable those protections. Do we really want to encourage people to
turn off security features for the sake of coding convenience?

Nat

Eric Mill

unread,
Aug 22, 2008, 11:04:07 AM8/22/08
to jest...@googlegroups.com
You're right, Nat. I think the solution here is as you suggest, adding
the ability to pass along arbitrary URL parameters to all actions, not
just #find.

Perhaps specifying a default set of accompanying URL params (in other
frameworks, this might be a "jsessionid", etc.) on the Resource
definition would work too. I envision that looking just like:

Resource.model("User", {
defaultParams: {
'authenticity_token': token,
'username': username,
'password': password
}
);

I'd encourage somebody to take that on by forking our repo on Github and
submitting a pull request.

-- Eric

Chad Pytel

unread,
Aug 22, 2008, 1:25:01 PM8/22/08
to jest...@googlegroups.com, jest...@googlegroups.com
I don't know how you can even find out the authenticity token from
rails. This would be key to get that to work, as far as I know it
changes for every request. In my opinion, this is really more of a
rails problem, then something for jester to solve with a custom
solution.

Nat Budin

unread,
Aug 22, 2008, 1:26:36 PM8/22/08
to jest...@googlegroups.com
It's easy:

<%= form_authenticity_token %>

Or if you want to be more sophisticated:

<% if protect_from_forgery? -%>
<%= form_authenticity_token %>
<% end -%>

Nat

Nat Budin

unread,
Aug 22, 2008, 1:31:25 PM8/22/08
to jest...@googlegroups.com
Thanks, Eric! I'll try and do a fork later today and see what I can
come up with.

Nat

Nat Budin

unread,
Aug 22, 2008, 3:05:02 PM8/22/08
to jest...@googlegroups.com
OK, forked, modified, pull request sent. Also includes unit tests!

This turned out to be somewhat more straightforward than I thought:
everything except obj.save is already using the _url_for helpers, and
already accepts arbitrary parameters being passed in. So all I needed
to modify was the _url_for function (to support model._defaultParams),
and the save function (which now uses the params+callback method
signature that everything else does).

I'm pretty sure this should cover all the cases necessary to use
Rails's forgery protection, but if it doesn't, I'll write back here
with my experiences.

Nat

On Fri, Aug 22, 2008 at 11:04 AM, Eric Mill <em...@thoughtbot.com> wrote:
>

Eric Mill

unread,
Aug 22, 2008, 3:06:55 PM8/22/08
to jest...@googlegroups.com
The proposed solution, setting default URL parameters for each request,
is something useful in general, that would also help with the Rails
authenticity token issue. Allowing URL parameters to be passed on
#create, #save, and #destroy is also a good piece of flexibility to add.

-- Eric

Eric Mill

unread,
Aug 22, 2008, 3:26:36 PM8/22/08
to jest...@googlegroups.com
Nat, you are a badass.

-- Eric

Chad Pytel

unread,
Aug 22, 2008, 3:58:43 PM8/22/08
to jest...@googlegroups.com
I agree, and its something that exists in Active Resource as well. I
remain to convinced that it'll actually work to solve the authenticity
token, because I still don't know how you get it from the server, but
thats without doing any research on it either.

-Chad

---
Chad Pytel, Founder and CEO
thoughtbot, inc.
organic brains. digital solutions.
-------------------------------------------
tel: 617.482.1300 x113
fax: 866.217.5992
http://www.thoughtbot.com


Chad Pytel

unread,
Aug 22, 2008, 4:00:35 PM8/22/08
to jest...@googlegroups.com
Ok, I see you responded. The forgery protection authenticity token
doesn't change with every new request?

-Chad

Nat Budin

unread,
Aug 22, 2008, 4:13:18 PM8/22/08
to jest...@googlegroups.com
I don't know how often it changes, but I now have some indication that
this actually works in a real-world Rails use case. I modified my
JIPE plugin to support cross-site request forgery protection using
this patch, and cursory testing indicates that it works as intended.
For the curious, you can find my changed version at:

http://github.com/nbudin/jipe/tree/master

I've tried doing multiple saves of the same object from the same page
without reloading, and it still seems to work fine.

Nat

Reply all
Reply to author
Forward
0 new messages