# Protect\_from\_forgery doesnt protect from forgery

**URL:** <https://www.ruby-forum.com/t/protect-from-forgery-doesnt-protect-from-forgery/169884>\
**Category:** Rails\
**Created:** [June 9, 2009, 11:12pm UTC](https://www.ruby-forum.com/t/protect-from-forgery-doesnt-protect-from-forgery/169884 "2009-06-09T23:12:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![c\_dekker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/b782af/32.png) [@c\_dekker](https://www.ruby-forum.com/u/c_dekker)\
**Post date:** [June 9, 2009, 11:12pm UTC](https://www.ruby-forum.com/t/protect-from-forgery-doesnt-protect-from-forgery/169884/1 "2009-06-09T23:12:44Z")

</div>

Maybe I am grasping the full usage of this protect\_from\_forgery  
function, but it does not seem to work for me. Imagine the following:

A simple website with a user that needs to log in to do certain stuff  
and a closed off admin section that only certain users can access that  
have the is\_admin field set to true.

So to be clear, my User model has a login, password and is\_admin.

When displaying the user’s ‘profile’, he can only edit his password. I  
dont want him editing his own login or ofcourse is\_admin status for  
obvious reasons.

Now when I use firebug and inspect the page, I see a neat little field  
containing the authenticity\_token.

But here it comes,

When I edit the page in firebug, and add a field called user\_is\_admin  
and set its value to 1, and then submit, the changes actually go  
through!! I have now made myself and admin.

Isnt protect\_from\_forgery supposed to protect from this? Obviously in  
the controller I have kept it simple and did a  
@user.update\_attributes(params[:user]), expecting that the  
authenticity\_token would never allow any params to be posted that I  
didnt allow through my form.

Did I do something wrong implementing this whole thing? I use the  
default cookie session store and still have the :secret key commented  
out, like how the project is generated.

This is with rails 2.3.2

---

<div class="post-metadata">

**Author:** ![c\_dekker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/b782af/32.png) [@c\_dekker](https://www.ruby-forum.com/u/c_dekker)\
**Post date:** [June 10, 2009, 12:26am UTC](https://www.ruby-forum.com/t/protect-from-forgery-doesnt-protect-from-forgery/169884/2 "2009-06-10T00:26:14Z")

</div>

> the controller I have kept it simple and did a  
> @user.update\_attributes(params[:user]), expecting that the  
> authenticity\_token would never allow any params to be posted that I  
> didnt allow through my form.

The forgery protect\_from\_forgery protects against is cross site  
request forgery, ie. completely unrelated to the problem you’re  
tackling. You may be interested in attr\_protected/attr\_accessible.

Fred

---

<div class="post-metadata">

**Author:** ![c\_dekker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/b782af/32.png) [@c\_dekker](https://www.ruby-forum.com/u/c_dekker)\
**Post date:** [June 11, 2009, 4:20pm UTC](https://www.ruby-forum.com/t/protect-from-forgery-doesnt-protect-from-forgery/169884/3 "2009-06-11T16:20:26Z")

</div>

Frederick C. wrote:

> > the controller I have kept it simple and did a  
> > @user.update\_attributes(params[:user]), expecting that the  
> > authenticity\_token would never allow any params to be posted that I  
> > didnt allow through my form.
> 
> The forgery protect\_from\_forgery protects against is cross site  
> request forgery, ie. completely unrelated to the problem you’re  
> tackling. You may be interested in attr\_protected/attr\_accessible.
> 
> Fred

Alright that makes sense. I might have misunderstood the PFF function.

But I still feel this is a grossly underestimated security hole. It  
doesn’t seem very ruby-esque to shield the ‘forbidden’ attributes with  
attr\_accessors. Since on one form you might be allowed to change it, yet  
on a different one you wont have that field supplied.

You obviously dont want to hard code your data entry restrictions on  
controller level. That violates the DRY principle. When I change the  
form to allow someone to edit an extra field, I also have to ‘open up’  
this field in the controller.

The form fields I specify in the form are the only fields the user is  
allowed to change on that particular entry point. How can I enforce that  
no extra fields are introduced?

I am thinking about an idea very similar to the authenticity token from  
protect\_from\_forgery. Create a hash based on all the fields in a form  
and some serverside secret. Whenever the post params come in I know  
which fields are posted so I can recreate this hash and compare.

Has this been done before? Or would I have to build this into a plugin  
from scratch?

---

<div class="post-metadata">

**Author:** ![c\_dekker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/b782af/32.png) [@c\_dekker](https://www.ruby-forum.com/u/c_dekker)\
**Post date:** [June 11, 2009, 6:13pm UTC](https://www.ruby-forum.com/t/protect-from-forgery-doesnt-protect-from-forgery/169884/4 "2009-06-11T18:13:40Z")

</div>

On Thu, Jun 11, 2009 at 4:20 PM, C, D.[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> this field in the controller.  
> The current solution is a trade-off: it is a simple solution that  
> covers most use cases. Often the account\_id of your User model is  
> protected, period. That’s what the current design supports.

There was a recent discussion in the core mailing list about possible  
ways to make this a little more flexible:

[http://groups.google.co.uk/group/rubyonrails-core/browse\_thread/thread/3b6818496d0d07f1/0d20bb9236fe59af#0d20bb9236fe59af](http://groups.google.co.uk/group/rubyonrails-core/browse_thread/thread/3b6818496d0d07f1/0d20bb9236fe59af#0d20bb9236fe59af)

but no conclusion except for some workarounds to the current solution  
when you need them.
