Imagine you have a user model with a user name and several other attributes. A user will only be able to set a username while singing up, not later when editing his profile.
Still, the :user_name attribute needs to accessible through attr_accessible in the user model for the registration form.
This makes me wonder whether a malicious user could change the form that allows him to edit his profile, and change an input name to user_name and thereby in fact change it upon submit.
Am I right about this, i.e. could a malicious user do that or will Ruby find out somehow that the form was altered? If this is a security issue, how can I always reset the user name in my update method? Is there a rails way of differentiating between accessible and accessible but non-editable attributes?
No, it's not possible due to Rails' CSRF counter measures. See this guide.
You should have the following line in your application controller:
protect_from_forgery :secret => "123456789012345678901234567890..."
Also have a look at the following article for further information on XSS, which describes in some detail what is possible and counter-measures to take.
Always sanitize() input.
Related
I would like to add a column to users called points, and update it at different times. However, when I change a value of a User column, the User is signed out, since the remember token for the user gets changed, and doesn't match the one stored locally.
I can manually sign in the user each time I update a column in the controller, but I want to avoid this if possible (and be able to update from the model). Is there a way I can update the User without signing them out?
I dont know what authentication system you are using, but just changing the schema or updating a user's attributes doesnt require a user to login again on most common rails auth systems (Devise, Authlogic, etc...)
The easiest thing would be to store #user.id in your session variable, rather than the whole User object. With that approach, even after editing, you will keep a stable id field that you can reference.
This has a few benefits:
It's more secure. Rails sessions are difficult to tamper, but easy to read. So you now don't have to worry about any secure or semisecure data in your session cookie that would be leaked by embedding the whole user
The whole object is potentially big. Every request has a serialized User object going back and forth for no good reason.
It's easy to wire this into your application controller so it's transparent that an id is used rather than a real User object.
class ApplicationController < ActionController::Base
def current_user
User.find(session[:user_id])
end
....
Of course you'll add error handling for a not-logged-in user, but that general approach will keep your code clean, and abstract away the a User's data contents from the idea of a User's identifier.
I realized the problem was a new token is generated with a before_save callback whenever a User is saved. So there are two ways I can fix this:
Change before_save to before_create.
User update_column to update a column without calling the before_save callbacks.
In my application I have two ways of singing up users:
Sign up form
Facebook Connect
In both ways we store information into the database, but just in the first want we want to store the password.
I have some password related validations that I want to be performed for the first way of users signing up, but I don't want it to happen for the second one. What would be the appropriate and secure way of doing this in Rails?
My first approach was creating an attribute for the user object called password_optional and do a conditional in the validation with that, but I'm not sure how can I set that attribute by default to false or set it to false when the user is signing up using the form.
If you don't have a password when user signs up via facebook, but your validation requires it, set it to some random string then.
This is exactly what is recommended in Devise documentation.
Skip the validations when you don't need it. There are multiple ways of doing that
Maybe you could have two models User::Normal < User and User::Facebook < User. Most of the logic goes into User, and specificities go into the custom models.
Maybe you could just go validates_presence_of :password, :if => not_facebook? or something of the sort.
I'm building a community website where users sign up and create profiles.
Now when a user has signed up they can click a link to take them to the edit profile area of the websites.
Here they can fill in their name, age, select, birthday and fill out things such as personal stats, about me etc.
I'm wondering what is the best way to protect my profiles table from malicious hackers? Most similar websites don't seem to have any kind of validation when it comes to their edit profile section of the website. So a user can fill in nothing and still submit a form with no issue.
I'm wonder what is the best way to allow this kind of functionality but at the same time protect my database?
Should I just be setting maximum length validation rules amongst other things?
I'm not quite sure how to deal with this.
I have drop down select menus, text area boxes, and plenty text fields which data about the user will be entered in to.
How would you deal with this and/or what is the most appropriate way to deal with this?
Kind regards
The most common threats to look out for are attempts to elevate privilege through this class. For instance if you have a user table with an admin attribute used to determine if a user is an admin, even if this attribute cannot be set in the form you describe a user can craft a post to the action of the form on the page with &admin=true or &admin=1 depending on the corresponding column data type.
The protection against this is specifying in your model the attributes that are updatable through mass-assignment.
You do this with the attr_accessible method.
attr_accessor :x, :y, :admin
attr_accessible :x, :y
This will prevent the admin attribute from being updated through an update_attributes call typically used in an edit action.
The other thing to watch out for is automated sign-ups. For this there are a couple of things you can do. The most common is to implement a captcha. Without this someone could write a script that creates 1_000_000 users in your table making it very difficult to determine which are real and which are fake. You may also think about logging sign-up attempts by IP and restricting the number of requests for an hours time, for instance.
As for your edit page protection, the most common way to protect this is to use a before_filter in your controller that makes sure the user has some piece of session information before allowing the page to be rendered.
class UsersController < ApplicationController
before_filter :protect, :only => [:edit]
private
def protect
unless current_user
redirect_to login_path
end
end
end
Just some examples. I'm sure there are many more ways to protect yourself but this will at least give you an idea of the places that need attention to prevent the most basic attempts at wrecking your day. The problem with this topic is that the techniques used to break/hijack your site are ever-evolving. Some people think they are covered and get hit anyway. Backup your data frequently via script, write other scripts that check the integrity of your database. If you see a sudden leap in user instances of the table you'll know something is up, review the logs and restore your data.
If your site is popular, it will get attacked, period.
Another thing regarding captcha, I've heard that ANYTHING displayed on a screen can be scraped by script so as safe as this may seem there are talented people out there that can dance around your security like the Macarena.
Be as proactive as possible and have your reactive measures well thought-out.
It would be difficult to list everything you need to do here to protect yourself against some sort of malicious user.
You should probably just read the Ruby on Rails Security Guide:
http://guides.rubyonrails.org/security.html
I'm trying to build the backend for a subscription-only area for a website.
When the customer first pays for the subscription, he is going to be registered automatically by a callback from an external app confirming the user has paid.
I want to create the user automatically with several blank attributes. Once the user tries to login for the first time, he has to change or update all of these attributes. Then I want to run the validation routine for the attributes.
Assume the user knows his username and first password as he completes the payment.
The authentication is currently being done with Devise, but it is subject to change.
How would you go about implementing this on Rails?
You could use :on => :update after the relevant validations to bypass them on registration. Then, create a before_filter that redirects logged in users to their profile edit page throughout your application if at least one required attribute is missing.
You can just .save(false) on creation to prevent the validation completely
Not as good of a solution for your problem, but for others like me who got here through Google...
http://guides.rubyonrails.org/v2.3.11/activerecord_validations_callbacks.html#skipping-validations
In my app, I have a "User" model, which includes a number of attributes including "has_admin_rights". If true, the user is an admin, if false, they aren't.
Each user has a profile, with their login name, email address, profile pic, etc.
If I'm logged in as a regular user, I can click on a page called "profile", and I can edit my own account, e.g. updating my email address, profile pic, password, whatever. I can ONLY edit my account, and no other.
If I'm logged in as an admin, I can do a little more: for example, I can make ANOTHER user an admin, or take away their admin rights.
Now, only an admin has access to the view where the "make admin" check box appears, but I have a feeling that simply restricting access to the view isn't sufficient.
What I'm concerned about is, since any user can edit their own profile, what's there to stop a user from submitting a custom form post, which has in it the "has_admin_rights"=>"1" parameter on their own account - thereby granting themselves admin access?
What I'm thinking is that, in the User controller, before applying any changes to the "has_admin_rights" field, that I need to check to make sure the user making the request is currently an admin - otherwise I ignore the request altogether, and make no changes.
in the User controller, before applying any changes to the "has_admin_rights" field, that I need to check to make sure the user making the request is currently an admin - otherwise I ignore the request altogether, and make no changes.
yes, exactly. Never trust the client; remember that anybody can just tweak the page directly with Firebug or whatever.
I'd also suggest that you consider adding an audit trail, and log something whenever one admin makes another user into an admin. Maybe also send email to all the admins for a particular group to let them know that an admin has been created (or that rights have been revoked).
attr_protected is pretty useful, too
class User < ActiveRecord::Base
attr_protected :is_admin
end
Add a before_save in your User model that performs this validation .
Ue attr_accessible which white list of model attributes that can be set via mass-assignment
class User < ActiveRecord::Base
attr_accessible :has_admin_rights
end
& in controller
#user.has_admin_rights = current_user.is_admin? "1" : "0"