Rails secure with hidden field and firebug? - ruby-on-rails

I am working on a web application and what is bothering me is the fact that users can use firebug to manipulate the code.
<%= form_for([#journal, #news]) do |f| %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<%= f.hidden_field :journal %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
routes.rb
resources :journal do
resources: news
end
The url appears like so mysite.com/journal/1/news/3. Since the journal id is in the url how can I prevent a user from changing journal id value of 1 to something like 2 or 3.
<input id="news_journal_id" type="hidden" value="1" name="news[journal_id]">

You can't. NEVER trust input from anywhere. Implement a server-side validation/role-model/access-limitation of any kind.

You can't prevent users from sending you modified input. You can (and should) check that input on the server instead of blindly accepting it.
If a user can't read/write this journal, redirect him to a corresponding page, etc.

You should use current_user associations to fetch any record, to make your application secure.
For example:
journal = currect_user.journals.find(params[:news][:journal_id])
journal.news.create(params[:news].except(:journal_id))

Related

Rails: Checking value selected in a drop-down and comparing to a value in database

I'm fairly new to Ruby on Rails and I'm building a customer database for my father's landscaping company as a pet project. I've run into a roadblock with some code.
I've got three tables interacting with each other here: Clients, Invoices and Services (nested under Invoices). In the clients table, there are prices stored for each service performed (e.g., cut, bushes, mulch). If the client doesn't receive that service, the entry is null. I've stored the prices this way because each client is charged a different set amount for a service depending on the size of their property.
When adding a service to an invoice, I want to check the service selected in the drop-down against the price set in the client table, and give an error if its null (if the customer doesn't receive that service). For example, if "Cut" is selected, I'd like to compared that to (I think) #invoice.client.cut
I'm not entirely sure where to start with this. How would you have code like this run when the submit button is clicked?
Thanks in advance for any and all help!
Here's what the form looks like in its current state:
<%= form_for [#invoice, #service] do |f| %>
<div class="control-group">
<%= f.label :name %>
<div class="controls">
<%= f.select(:name, options_for_select([['Cut', 'Cut'], ["Mulch", "Mulch"],['Bushes', 'Bush'], ['Spring clean-up', 'Spring'], ['Fall clean-up', 'Fall'], ['Snow removal', 'Snow']])) %>
</div>
</div>
<div class="control-group">
<%= f.label :category %><br>
<div class="controls">
<%= f.select(:category, options_for_select([["Maintenance", "Maintenance"], ["Seasonal", "Seasonal"]])) %>
</div>
</div>
<div class="field">
<%= f.label :quantity %><br>
<%= f.number_field :quantity %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I would add at data-attribute somewhere in the view that lists the customer's current services, possible on the label for that dropdown. You can then use javascript to verify that the option selected is available to the user without making a call to the database.
<%= f.label :name, 'data-services' => #invoice.client.services %>
Instead of checking the validity of the selected value when the user chooses it, don't even show the value in the dropdown. The user experience is different than you described, but not necessarily worse.
The architecture of querying the different kinds of services a client has should be improved by an extra model, but using the methods you already have:
<%= f.select(
:name,
options_for_select(
[
['Cut', 'Cut'],
['Mulch', 'Mulch'],
['Bushes', 'Bush'],
['Spring clean-up', 'Spring'],
['Fall clean-up', 'Fall'],
['Snow removal', 'Snow']
].select do |a|
#invoice.client.public_send(a.last.downcase)
end
)
) %>

RoR MongoDB Arrayfield usage

i'm new to MongoDB and unsure how to use the Array-Field-Type.
So i created in my model
field :admins, type: Array
in this field i wanna store all user_ids that are "admins" of the model. But when I try to set this field, it doesnt save the Information in the Array it just simple creates an String with the ID. And due to my constrain that only Admins can edit my filter function
def check_if_admin
unless Agency.find(params[:id]).admins.include?(current_agent.id)
flash[:notice] = "Only possible as Admin."
redirect_to root_path
end
end
gets the error that
"can't convert Moped::BSON::ObjectId into String"
So I tried to initiate my field with in the create def as an array with ID:
#agency.admins = [current_agent.id]
That does the Trick for one user in the Array but how do I add IDs to this field?
When I go into my Edit Form:
<%= form_for(#agency) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :admins %><br />
<%= f.text_field :admins %> <br />
</div>
<div class="field">
<%= f.label :agents %><br />
<%= f.text_field :agents %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And Type in another User_ID by hand, I'm back to my error again.
Anyone knows how to get around that?
Thanks a ton for ur help!
This message means that at some point you stored a string where there should be an ObjectId. Ruby is trying to compare current_agent.id (an ObjectId) with params[:id] (a string).
It seems like you are not converting the input from the text_field in the form to an ObjectID before you push it onto the array.
Take the input from the admins field and make ObjectId's like this:
BSON::ObjectId.new(string_representing_admin_id)
I'm guessing the admins field is a comma separated array of admin _ids and that you are using some _id values that are easy to work with, like a username instead of a generated ObjectId as this would be very burdensome to work with.
In that case you would probably split and strip the input and then make an array of the ObjectIds using a map/select.
It would be much easier to use a select field that displayed usernames for something like this in rails right?
Anyway, show some sample documents from the collection if you need more help.

How should I handle this Rails use case?

I have an Exercise model, which has these columns (pseudo Ruby):
model Exercise do
string :name
calories_burned :float
end
I want that when a user adds an exercise to be able to do it in this fashion:
if previous exercises exist
show a select element with names of existing added
show a checkbox to allow adding a new one, switching the input
field to a textfield
else
show a textfield
The thing is, I don't know how I should put this in my view. Here's how the else case is handled:
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
I have something like this now:
<div class="field">
<% if #exercise_added %>
<div id="select_div">
<%= select_tag :name,options_for_select(#exercise_added) %>
<input type="checkbox" name="custom_type_checked" id="which_type">New type?</input>
</div>
<% end %>
<div id="regular_field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
</div>
In #exercise_added I have a list of names of all exercises from the database. What would be the best/cleanest way of handling this?
EDIT: For now,I have a textfield and a select, and by using Javascript, I'm changing the name of the element ( and hiding the other one ). So far, it's working, but I'd still be interested if other approaches exist.
You can check if the array #exercise_added is empty or not and show the select field or text field accordingly.
<div class="field">
<% if !#exercise_added.empty? %>
<div id="select_div">
<%= select_tag :name,options_for_select(#exercise_added) %>
<input type="checkbox" name="custom_type_checked" id="which_type">New type?</input>
</div>
<% else %>
<div id="regular_field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%end%>
</div>
I would, by default, have the select box and a button shown, with the textbox hidden unless a variable #show_textbox is true. Something like this:
<div class="field">
<div id="select_div">
<%= select_tag :name,options_for_select(#exercise_added) %>
<%= f.submit "New Exercise" %>
</div>
<div id="regular_field" <%= hidden_unless #show_textbox %> >
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
</div>
Where I've written a helper function
def hidden_unless cond
raw "style=\"display: none;\"" unless cond
end
# this one is helpful, too
def hidden_if cond
raw "style=\"display: none;\"" if cond
end
Then, in my controller, check if the "New Exercise" button was pressed. If so, essentially set #show_textbox to true and then re-render the new form.
def create
# .....
# did we get here because the user pressed "New Exercise"?
if params[:commit].eql?("New Exercise")
#show_textbox = true
# probably some other code to replicate what happens in your #new action
render :action => new
end
# ....
end
You can check in your controller if the :name field has any text in it, and use that to override the select box.
This should work without javascript. I'd add some jQuery to replace the button with either a link or a check box, with the click handler for that connected to a function that shows the textbox, i.e. $('#regular_field').toggle();.
I didn't deal with hiding the select box. I actually think it might be better to leave that available. You could hide it using a similar method, anyways.
What if you used two forms? One form to handle the case when the exercise is in #exercise_added, and a second form to handle the creation of a new exercise. It might even boil down to the difference between a POST and a PUT, depending on what you're doing once an exercise is submitted from the drop-down list.
I'd be curious to see more of the code, as well as the controller, since it seems like this form might be nested?

file_field is not sticky in my Rails form

I have a pretty standard Rails form:
<div>
<h1>Create a New Listing</h1>
<%- form_for #listing, :html => {:multipart => true} do |f| -%>
<div><%= f.label :title, "Title:"%> <%= f.text_field :title %></div>
<div>
<%= f.label :image, "Image:" %> <%= f.file_field :image
</div>
<div>
<%= f.label :sound, "Sound Clip:"%> <%= f.file_field :sound %><br />
</div>
<div class="submit"><%= f.submit 'Post Listing' %></div>
<%- end -%>
</div>
When a user chooses a file, but the form fails for validation purposes, he must always re-select the file. It is not sticky. Any suggestion on how to fix this?
Thanks!
You can't make the file field sticky, I think. Even if Rails provides the initial value, most browsers will just ignore it (or otherwise, some smart-aleck could set the default file to /etc/passwd, and if you don't pay attention, next thing you know your box is rooted.
The best you can do that I can think of is set a flag that says a file has already been uploaded, so if the user does not select another one, use the one already sent in the last request.
UPDATE: You'd be surprised how many people have no security skills whatsoever. I've known people to use a browser as root. However, "why" is not exactly an issue - the important point I was trying to make is just that it's not Rails's fault, the problem most likely lies in the browser behaviour.
You can read an article that says it better than I can...
UPDATE 2: "Your box is rooted" should say "the user's box is rooted". The scenario I describe is this: User submits a file innocent.txt and a CAPTCHA. Malicious server responds CAPTCHA is wrong, enter it again, and covertly changes the file from innocent.txt to ~/.ssh/id_rsa. User does not look at the file field (he already put in the correct value there), so just redoes the CAPTCHA and pushes submit. Now the server has the user's private SSH key.

React: form building in a Rails-like way

I am trying to enhance an existing Rails application using React (react-rails gem).
This app has a form built with following code:
<%= form_for #article do |f| %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body, size: "60x12" %>
</div>
<div class="form-group">
<label><%= f.checkbox :sets_expiration_date %> Sets expiration date</label>
<%= f.date_select :expiration_date, start_year: Date.today.year %>
</div>
<button type="submit" class="btn btn-default">Create</button>
<% end %>
I want this form to have following functionalities:
When the user toggles the checkbox, the three drop-down lists for the expiration_date field shows or hides.
When the user submits, the form data is sent to the server via Ajax for validation and persistence.
When the validation fails, the relevant labels and input fields get surrounded with red border.
When the form data gets saved successfully, the form disappears and a message appears.
In my first attempt, I managed to achieve the goal but I found that I had to write vanilla HTML code a lot.
This is a disappointment for me.
Especially, I don't like to specify the name and defaultValue attributes for each <input> tag
like <input name="article[title]" defaultValue={this.props.object.title}>.
I also had to write rather long JavaScript code to create three drop-down lists for the expiration_date field.
How can I construct such a form using React efficiently? Are there any good plugins?

Resources