frontcodelover
frontcodelover

Reputation: 337

Form hidden fields and security

I m using hidden field in my app to add user_id to my database "Camping". I have associations "User" has many campings and "Camping" belongs_to "user".

When I run firebug or something like this, I can modify user_id value of this field. If any user puts his ID, I can modify object to other user... I want to avoid this !

My code

<%= f.hidden_field :user_id, :value => current_user.id %>

This code, is necessary because I allow only user to edit / updated / create object if they have user_id == current_user.id. How to fix this security problem ?

By the way, I m using devise.

Edit with full code

My _form.html.erb

    <%= form_for(camping) do |f| %>
      <% if camping.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(camping.errors.count, "error") %> prohibited this camping from being saved:</h2>
          <ul>
          <% camping.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <%= f.hidden_field :user_id, :value => current_user.id %>

    <div class="form-group">
       <label for="name">Nom du camping</label>
          <%= f.text_field :name, autofocus: true, class:"form-control", id:"name", :required => true%>
      </div>

  <div class="actions">
    <%= f.submit "Enregistrer", class:"btn btn-success" %>
  </div>
<% end %>

my controller

    def new
          @camping = Camping.new
          @campings = Camping.all
        end


        def edit

        end
def create
      @camping = Camping.new(camping_params)
      respond_to do |format|
        if @camping.save
          format.html { redirect_to @camping, notice: 'Camping was successfully created.' }
          format.json { render :show, status: :created, location: @camping }
        else
          format.html { render :new }
          format.json { render json: @camping.errors, status: :unprocessable_entity }
        end
      end
    end

    def update
      @camping = Camping.find(params[:id])
      respond_to do |format|
        if @camping.update(camping_params)
          format.html { redirect_to @camping, notice: 'Camping was successfully updated.' }
          format.json { render :show, status: :ok, location: @camping }
        else
          format.html { render :edit }
          format.json { render json: @camping.errors, status: :unprocessable_entity }
        end
      end
    end

my edit.html.erb

<div class="containershow">
<h1>Editing Camping</h1>

<%= render 'form', camping: @camping %>

<%= link_to 'Show', @camping %> |
<%= link_to 'Back', campings_path %>
</div>

my new.html.erb

<h1>New Camping</h1>

<%= render 'form', camping: @camping %>

<%= link_to 'Back', campings_path %>

Edit solution ?

User can create and update his camping. I delete hidden_field

 def create
     # @camping = Camping.new(camping_params)

        @camping = Camping.new((camping_params).merge(:user_id => current_user.id))

      respond_to do |format|
        if @camping.save
          format.html { redirect_to @camping, notice: 'Camping was successfully created.' }
          format.json { render :show, status: :created, location: @camping }
        else
          format.html { render :new }
          format.json { render json: @camping.errors, status: :unprocessable_entity }
        end
      end
    end

Upvotes: 1

Views: 1251

Answers (2)

Gabor Lengyel
Gabor Lengyel

Reputation: 15599

In Devise, the current user object is in current_user, available to your controllers. When saving the model, make sure to fill the user id field from that object, and not user input in the update action of your controller. Note that the edit action does not matter, that just renders the edit page, the actual update happens in update (if you follow the default conventions). Of course if you don't want users to even see other users' objects, you also need access control in other controller actions like edit as well, but that (implementing access control in a multi-tenant Rails application) is a different and much broader question.

More generally, be aware that anything that comes from a request can very easily be forged by a user. Always implement security server-side and do not trust user input!

Edit (seeing your code)

To prevent users updating others' Campings, you need to check in update after getting the @camping object (the second line) whether that's a camping object that your logged on user (current_user.id) is supposed to be able to edit.

The same way, if you want to prevent users from creating Campings for other users, you need to make sure in create that user_id will be set to the current user, something like @camping.user_id=current_user.id.

Similarly, if you want to prevent having a look at each other's Campings, you need to add checks to edit, show and pretty much all actions that return such objects.

There are gems like cancan and cancancan that may help with access control in Rails, they are worth a look!

Upvotes: 2

Tushar Pal
Tushar Pal

Reputation: 523

Your Question is quite interesting but simple In the any HTML View Any one can change anything this will cause a security wise vulnerability as well.

To avoid these issues we need to authenticate it by two way You have to check the code by like It should be use by Controller not by view.

Suppose If you are creating any article of particular user

So To avoid it what you can do You can set the User ID in Session and make a Helper Method to find Current User always

So that you can find current user directly from controller and create article according to user

  def Create

   @article = current_user.articles.create(article_params)

  end

This kind of Two way checking you can put up so that It will be safe.

To avoid the spend time on these work you can use gem directly like Devise

Upvotes: 1

Related Questions