Andrew
Andrew

Reputation: 43123

Ruby: Variable variable / method call + security concerns

So, this is a rails app but really more of a general ruby question:

I have a model with several scopes. For example:

Photo.recent
Photo.popular
Photo.featured

I have a "browse photos" view in my app where I want to be able to pass a single param and let the user specify a scope they want to view, ie:

example.com/photos/browse?view=recent

This gives me params[:view], and I need to attach that as a method call on Photo.

So my first question is, how can you do that kind of thing in Ruby?

Second, this could be a security risk if I can't constrain the input, if I just attach Photo.whatever the user types in the url then I'm at risk for a hacker saying example.com/photos/browse?view=delete_all That, obviously, is a bad idea.

So my second question is, how can I create a whitelist or something for what can be called -- or even better setup some kind of method that can accept the param from the URL safely and only return information if the user is requesting a valid named scope.

Lastly, I have some scopes that are only for admins. I have user abilities defined (using CanCan) so I can query current_user.has_role? to check if a user is authorized for anything, but is there a way to associate permissions with a scope?

Thanks!

Upvotes: 0

Views: 206

Answers (2)

Jamie Wong
Jamie Wong

Reputation: 18350

TBH, unless you have a lot of these scopes, I would just hardcode them or create a hash mapping the url param values to lambdas

In the event that you do want to do exactly what you said, you could do something like:

whitelist = %w(
  recent
  popular
  featured
)

if whitelist.include? params[:view]
  photos = Photo.send params[:view].to_sym
end

See: http://apidock.com/ruby/Object/send

EDIT: Perhaps try this?

if Photo.valid_scope_name? params[:view]
  photos = Photo.send params[:view].to_sym
end

It's a protected method, so you might have to use:

if Photo.send :valid_scope_name?, params[:view]
  photos = Photo.send params[:view].to_sym
end

http://apidock.com/rails/ActiveRecord/NamedScope/ClassMethods/valid_scope_name%3F

Upvotes: 2

sethvargo
sethvargo

Reputation: 26997

To send a method, use the send method :)

Photo.send(params[:view].to_sym)

However, you are 100% correct to assume this (might) be a security concern. Subsequently, you may want to do something like the following:

Photo.send(params[:view].to_sym) if %w(recent popular featured).include?(params[:view])

Upvotes: 1

Related Questions